diff options
49 files changed, 1001 insertions, 891 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock index 8299dea1c4b..09baaeadaee 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -44,7 +44,7 @@ dependencies = [ "html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -342,10 +342,10 @@ name = "clippy_lints" version = "0.0.212" dependencies = [ "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -887,14 +887,14 @@ name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "if_chain" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1153,7 +1153,7 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2868,7 +2868,7 @@ name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2932,7 +2932,7 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3123,7 +3123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b04478cf718862650a0bf66acaf8f2f8c906fbc703f35c916c1f4211b069a364" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" +"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec" "checksum ignore 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "787a5940ab88e0f2f3b2cad3687060bddcf67520f3b761abc31065c9c495d088" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" "checksum isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6c324313540cd4d7ba008d43dc6606a32a5579f13cc17b2804c13096f0a5c522" @@ -3148,7 +3148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" "checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" -"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 931c28f1ca9..b1ee636644e 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -99,7 +99,7 @@ objdir=$root_dir/obj mkdir -p $HOME/.cargo mkdir -p $objdir/tmp -mkdir $objdir/cores +mkdir -p $objdir/cores args= if [ "$SCCACHE_BUCKET" != "" ]; then diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 19bdcbc6ad6..0ae45b31232 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -103,7 +103,7 @@ impl<K, V> LeafNode<K, V> { } fn is_shared_root(&self) -> bool { - self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V> + ptr::eq(self, &EMPTY_ROOT_NODE as *const _ as *const _) } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index bbe6ae8619f..72074e1dbce 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -244,9 +244,6 @@ macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*) #[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 mod coresimd; -#[unstable(feature = "stdsimd", issue = "48556")] -#[cfg(not(stage0))] -pub use coresimd::simd; #[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(not(stage0))] pub use coresimd::arch; diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index e4a4e33c172..28ef53ccb5c 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -48,7 +48,6 @@ impl<T> RawArray<T> { /// # Safety /// /// The specified range must be valid for reading and writing. -/// The type `T` must have non-zero size. /// /// # Algorithm /// @@ -73,6 +72,7 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mid: *mut T, mut right: usize) { loop { let delta = cmp::min(left, right); if delta <= RawArray::<T>::cap() { + // We will always hit this immediately for ZST. break; } diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs index 06939a9d1e1..51e7647f36c 100644 --- a/src/libproc_macro/diagnostic.rs +++ b/src/libproc_macro/diagnostic.rs @@ -10,7 +10,8 @@ use Span; -use rustc_errors as rustc; +use rustc_errors as errors; +use syntax_pos::MultiSpan; /// An enum representing a diagnostic level. #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] @@ -97,38 +98,21 @@ impl Diagnostic { /// Emit the diagnostic. #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn emit(self) { - ::__internal::with_sess(move |sess, _| { - let handler = &sess.span_diagnostic; - let level = __internal::level_to_internal_level(self.level); - let mut diag = rustc::DiagnosticBuilder::new(handler, level, &*self.message); + let level = self.level.to_internal(); + let mut diag = errors::Diagnostic::new(level, &*self.message); - if let Some(span) = self.span { - diag.set_span(span.0); - } + if let Some(span) = self.span { + diag.set_span(span.0); + } - for child in self.children { - let span = child.span.map(|s| s.0); - let level = __internal::level_to_internal_level(child.level); - diag.sub(level, &*child.message, span); - } + for child in self.children { + let span = child.span.map_or(MultiSpan::new(), |s| s.0.into()); + let level = child.level.to_internal(); + diag.sub(level, &*child.message, span, None); + } - diag.emit(); + ::__internal::with_sess(move |sess, _| { + errors::DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, diag).emit(); }); } } - -#[unstable(feature = "proc_macro_internals", issue = "27812")] -#[doc(hidden)] -pub mod __internal { - use super::{Level, rustc}; - - pub fn level_to_internal_level(level: Level) -> rustc::Level { - match level { - Level::Error => rustc::Level::Error, - Level::Warning => rustc::Level::Warning, - Level::Note => rustc::Level::Note, - Level::Help => rustc::Level::Help, - Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive") - } - } -} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f5a7c88a1b7..61da9db76f6 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -44,21 +44,24 @@ extern crate syntax_pos; extern crate rustc_errors; extern crate rustc_data_structures; +#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[doc(hidden)] +pub mod rustc; + mod diagnostic; #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub use diagnostic::{Diagnostic, Level}; use std::{ascii, fmt, iter}; +use std::path::PathBuf; use rustc_data_structures::sync::Lrc; use std::str::FromStr; -use syntax::ast; use syntax::errors::DiagnosticBuilder; use syntax::parse::{self, token}; -use syntax::symbol::{keywords, Symbol}; +use syntax::symbol::Symbol; use syntax::tokenstream; -use syntax::parse::lexer::{self, comments}; use syntax_pos::{FileMap, Pos, FileName}; /// The main type provided by this crate, representing an abstract stream of @@ -145,6 +148,9 @@ impl fmt::Debug for TokenStream { } } +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub use quote::{quote, quote_span}; + /// Creates a token stream containing a single token tree. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl From<TokenTree> for TokenStream { @@ -237,7 +243,7 @@ pub mod token_stream { /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. /// -/// This is a dummy macro, the actual implementation is in quote::Quoter +/// This is a dummy macro, the actual implementation is in `quote::quote`.` #[unstable(feature = "proc_macro_quote", issue = "38356")] #[macro_export] macro_rules! quote { () => {} } @@ -246,13 +252,6 @@ macro_rules! quote { () => {} } #[doc(hidden)] mod quote; -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -#[unstable(feature = "proc_macro_quote", issue = "38356")] -pub fn quote_span(span: Span) -> TokenStream { - quote::Quote::quote(span) -} - /// A region of source code, along with macro expansion information. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Copy, Clone)] @@ -425,8 +424,11 @@ impl SourceFile { /// /// [`is_real`]: #method.is_real #[unstable(feature = "proc_macro_span", issue = "38356")] - pub fn path(&self) -> &FileName { - &self.filemap.name + pub fn path(&self) -> PathBuf { + match self.filemap.name { + FileName::Real(ref path) => path.clone(), + _ => PathBuf::from(self.filemap.name.to_string()) + } } /// Returns `true` if this source file is a real source file, and not generated by an external @@ -440,18 +442,12 @@ impl SourceFile { } } -#[unstable(feature = "proc_macro_span", issue = "38356")] -impl AsRef<FileName> for SourceFile { - fn as_ref(&self) -> &FileName { - self.path() - } -} #[unstable(feature = "proc_macro_span", issue = "38356")] impl fmt::Debug for SourceFile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SourceFile") - .field("path", self.path()) + .field("path", &self.path()) .field("is_real", &self.is_real()) .finish() } @@ -467,13 +463,6 @@ impl PartialEq for SourceFile { #[unstable(feature = "proc_macro_span", issue = "38356")] impl Eq for SourceFile {} -#[unstable(feature = "proc_macro_span", issue = "38356")] -impl PartialEq<FileName> for SourceFile { - fn eq(&self, other: &FileName) -> bool { - self.as_ref() == other - } -} - /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] @@ -599,7 +588,7 @@ impl fmt::Display for TokenTree { /// A delimited token stream. /// /// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone, Debug)] +#[derive(Clone)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Group { delimiter: Delimiter, @@ -693,12 +682,23 @@ impl fmt::Display for Group { } } +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Group { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Group") + .field("delimiter", &self.delimiter()) + .field("stream", &self.stream()) + .field("span", &self.span()) + .finish() + } +} + /// An `Punct` is an single punctuation character like `+`, `-` or `#`. /// /// Multicharacter operators like `+=` are represented as two instances of `Punct` with different /// forms of `Spacing` returned. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Punct { ch: char, spacing: Spacing, @@ -782,8 +782,19 @@ impl fmt::Display for Punct { } } +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Punct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Punct") + .field("ch", &self.as_char()) + .field("spacing", &self.spacing()) + .field("span", &self.span()) + .finish() + } +} + /// An identifier (`ident`). -#[derive(Clone, Debug)] +#[derive(Clone)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Ident { sym: Symbol, @@ -797,6 +808,16 @@ impl !Send for Ident {} impl !Sync for Ident {} impl Ident { + fn is_valid(string: &str) -> bool { + let mut chars = string.chars(); + if let Some(start) = chars.next() { + (start == '_' || start.is_xid_start()) + && chars.all(|cont| cont == '_' || cont.is_xid_continue()) + } else { + false + } + } + /// Creates a new `Ident` with the given `string` as well as the specified /// `span`. /// The `string` argument must be a valid identifier permitted by the @@ -818,26 +839,19 @@ impl Ident { /// tokens, requires a `Span` to be specified at construction. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn new(string: &str, span: Span) -> Ident { - if !lexer::is_valid_ident(string) { + if !Ident::is_valid(string) { panic!("`{:?}` is not a valid identifier", string) } - Ident { - sym: Symbol::intern(string), - span, - is_raw: false, - } + Ident::new_maybe_raw(string, span, false) } /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). #[unstable(feature = "proc_macro_raw_ident", issue = "38356")] pub fn new_raw(string: &str, span: Span) -> Ident { - let mut ident = Ident::new(string, span); - if ident.sym == keywords::Underscore.name() || - ast::Ident::with_empty_ctxt(ident.sym).is_path_segment_keyword() { - panic!("`{:?}` is not a valid raw identifier", string) + if !Ident::is_valid(string) { + panic!("`{:?}` is not a valid identifier", string) } - ident.is_raw = true; - ident + Ident::new_maybe_raw(string, span, true) } /// Returns the span of this `Ident`, encompassing the entire string returned @@ -859,10 +873,17 @@ impl Ident { #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.is_raw { - f.write_str("r#")?; - } - self.sym.as_str().fmt(f) + TokenStream::from(TokenTree::from(self.clone())).fmt(f) + } +} + +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Ident") + .field("ident", &self.to_string()) + .field("span", &self.span()) + .finish() } } @@ -870,11 +891,12 @@ impl fmt::Display for Ident { /// character (`'a'`), byte character (`b'a'`), an integer or floating point number /// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). /// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. +// FIXME(eddyb) `Literal` should not expose internal `Debug` impls. #[derive(Clone, Debug)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Literal { lit: token::Lit, - suffix: Option<ast::Name>, + suffix: Option<Symbol>, span: Span, } @@ -1122,236 +1144,6 @@ impl fmt::Display for Literal { } } -impl Delimiter { - fn from_internal(delim: token::DelimToken) -> Delimiter { - match delim { - token::Paren => Delimiter::Parenthesis, - token::Brace => Delimiter::Brace, - token::Bracket => Delimiter::Bracket, - token::NoDelim => Delimiter::None, - } - } - - fn to_internal(self) -> token::DelimToken { - match self { - Delimiter::Parenthesis => token::Paren, - Delimiter::Brace => token::Brace, - Delimiter::Bracket => token::Bracket, - Delimiter::None => token::NoDelim, - } - } -} - -impl TokenTree { - fn from_internal(stream: tokenstream::TokenStream, stack: &mut Vec<TokenTree>) - -> TokenTree { - use syntax::parse::token::*; - - let (tree, is_joint) = stream.as_tree(); - let (span, token) = match tree { - tokenstream::TokenTree::Token(span, token) => (span, token), - tokenstream::TokenTree::Delimited(span, delimed) => { - let delimiter = Delimiter::from_internal(delimed.delim); - let mut g = Group::new(delimiter, TokenStream(delimed.tts.into())); - g.set_span(Span(span)); - return g.into() - } - }; - - let op_kind = if is_joint { Spacing::Joint } else { Spacing::Alone }; - macro_rules! tt { - ($e:expr) => ({ - let mut x = TokenTree::from($e); - x.set_span(Span(span)); - x - }) - } - macro_rules! op { - ($a:expr) => (tt!(Punct::new($a, op_kind))); - ($a:expr, $b:expr) => ({ - stack.push(tt!(Punct::new($b, op_kind))); - tt!(Punct::new($a, Spacing::Joint)) - }); - ($a:expr, $b:expr, $c:expr) => ({ - stack.push(tt!(Punct::new($c, op_kind))); - stack.push(tt!(Punct::new($b, Spacing::Joint))); - tt!(Punct::new($a, Spacing::Joint)) - }) - } - - match token { - Eq => op!('='), - Lt => op!('<'), - Le => op!('<', '='), - EqEq => op!('=', '='), - Ne => op!('!', '='), - Ge => op!('>', '='), - Gt => op!('>'), - AndAnd => op!('&', '&'), - OrOr => op!('|', '|'), - Not => op!('!'), - Tilde => op!('~'), - BinOp(Plus) => op!('+'), - BinOp(Minus) => op!('-'), - BinOp(Star) => op!('*'), - BinOp(Slash) => op!('/'), - BinOp(Percent) => op!('%'), - BinOp(Caret) => op!('^'), - BinOp(And) => op!('&'), - BinOp(Or) => op!('|'), - BinOp(Shl) => op!('<', '<'), - BinOp(Shr) => op!('>', '>'), - BinOpEq(Plus) => op!('+', '='), - BinOpEq(Minus) => op!('-', '='), - BinOpEq(Star) => op!('*', '='), - BinOpEq(Slash) => op!('/', '='), - BinOpEq(Percent) => op!('%', '='), - BinOpEq(Caret) => op!('^', '='), - BinOpEq(And) => op!('&', '='), - BinOpEq(Or) => op!('|', '='), - BinOpEq(Shl) => op!('<', '<', '='), - BinOpEq(Shr) => op!('>', '>', '='), - At => op!('@'), - Dot => op!('.'), - DotDot => op!('.', '.'), - DotDotDot => op!('.', '.', '.'), - DotDotEq => op!('.', '.', '='), - Comma => op!(','), - Semi => op!(';'), - Colon => op!(':'), - ModSep => op!(':', ':'), - RArrow => op!('-', '>'), - LArrow => op!('<', '-'), - FatArrow => op!('=', '>'), - Pound => op!('#'), - Dollar => op!('$'), - Question => op!('?'), - SingleQuote => op!('\''), - - Ident(ident, false) => { - tt!(self::Ident::new(&ident.as_str(), Span(span))) - } - Ident(ident, true) => { - tt!(self::Ident::new_raw(&ident.as_str(), Span(span))) - } - Lifetime(ident) => { - let ident = ident.without_first_quote(); - stack.push(tt!(self::Ident::new(&ident.as_str(), Span(span)))); - tt!(Punct::new('\'', Spacing::Joint)) - } - Literal(lit, suffix) => tt!(self::Literal { lit, suffix, span: Span(span) }), - DocComment(c) => { - let style = comments::doc_comment_style(&c.as_str()); - let stripped = comments::strip_doc_comment_decoration(&c.as_str()); - let stream = vec![ - tt!(self::Ident::new("doc", Span(span))), - tt!(Punct::new('=', Spacing::Alone)), - tt!(self::Literal::string(&stripped)), - ].into_iter().collect(); - stack.push(tt!(Group::new(Delimiter::Bracket, stream))); - if style == ast::AttrStyle::Inner { - stack.push(tt!(Punct::new('!', Spacing::Alone))); - } - tt!(Punct::new('#', Spacing::Alone)) - } - - Interpolated(_) => { - __internal::with_sess(|sess, _| { - let tts = token.interpolated_to_tokenstream(sess, span); - tt!(Group::new(Delimiter::None, TokenStream(tts))) - }) - } - - DotEq => op!('.', '='), - OpenDelim(..) | CloseDelim(..) => unreachable!(), - Whitespace | Comment | Shebang(..) | Eof => unreachable!(), - } - } - - fn to_internal(self) -> tokenstream::TokenStream { - use syntax::parse::token::*; - use syntax::tokenstream::{TokenTree, Delimited}; - - let (ch, kind, span) = match self { - self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()), - self::TokenTree::Group(tt) => { - return TokenTree::Delimited(tt.span.0, Delimited { - delim: tt.delimiter.to_internal(), - tts: tt.stream.0.into(), - }).into(); - }, - self::TokenTree::Ident(tt) => { - let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw); - return TokenTree::Token(tt.span.0, token).into(); - } - self::TokenTree::Literal(self::Literal { - lit: Lit::Integer(ref a), - suffix, - span, - }) - if a.as_str().starts_with("-") => - { - let minus = BinOp(BinOpToken::Minus); - let integer = Symbol::intern(&a.as_str()[1..]); - let integer = Literal(Lit::Integer(integer), suffix); - let a = TokenTree::Token(span.0, minus); - let b = TokenTree::Token(span.0, integer); - return vec![a, b].into_iter().collect() - } - self::TokenTree::Literal(self::Literal { - lit: Lit::Float(ref a), - suffix, - span, - }) - if a.as_str().starts_with("-") => - { - let minus = BinOp(BinOpToken::Minus); - let float = Symbol::intern(&a.as_str()[1..]); - let float = Literal(Lit::Float(float), suffix); - let a = TokenTree::Token(span.0, minus); - let b = TokenTree::Token(span.0, float); - return vec![a, b].into_iter().collect() - } - self::TokenTree::Literal(tt) => { - let token = Literal(tt.lit, tt.suffix); - return TokenTree::Token(tt.span.0, token).into() - } - }; - - let token = match ch { - '=' => Eq, - '<' => Lt, - '>' => Gt, - '!' => Not, - '~' => Tilde, - '+' => BinOp(Plus), - '-' => BinOp(Minus), - '*' => BinOp(Star), - '/' => BinOp(Slash), - '%' => BinOp(Percent), - '^' => BinOp(Caret), - '&' => BinOp(And), - '|' => BinOp(Or), - '@' => At, - '.' => Dot, - ',' => Comma, - ';' => Semi, - ':' => Colon, - '#' => Pound, - '$' => Dollar, - '?' => Question, - '\'' => SingleQuote, - _ => unreachable!(), - }; - - let tree = TokenTree::Token(span.0, token); - match kind { - Spacing::Alone => tree.into(), - Spacing::Joint => tree.joint(), - } - } -} - /// Permanently unstable internal implementation details of this crate. This /// should not be used. /// @@ -1364,8 +1156,6 @@ impl TokenTree { #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] pub mod __internal { - pub use quote::{LiteralKind, SpannedSymbol, Quoter, unquote}; - use std::cell::Cell; use std::ptr; diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index 73a66640c59..7ae7b13a152 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -14,35 +14,26 @@ //! This quasiquoter uses macros 2.0 hygiene to reliably access //! items from `proc_macro`, to build a `proc_macro::TokenStream`. -use {Delimiter, Literal, Spacing, Span, Ident, Punct, Group, TokenStream, TokenTree}; - -use syntax::ext::base::{ExtCtxt, ProcMacro}; -use syntax::parse::token; -use syntax::symbol::Symbol; -use syntax::tokenstream; - -/// This is the actual quote!() proc macro -/// -/// It is manually loaded in CStore::load_macro_untracked -pub struct Quoter; - -pub fn unquote<T: Into<TokenStream> + Clone>(tokens: &T) -> TokenStream { - tokens.clone().into() -} - -pub trait Quote { - fn quote(self) -> TokenStream; -} - -macro_rules! tt2ts { - ($e:expr) => (TokenStream::from(TokenTree::from($e))) -} - -macro_rules! quote_tok { - (,) => { tt2ts!(Punct::new(',', Spacing::Alone)) }; - (.) => { tt2ts!(Punct::new('.', Spacing::Alone)) }; - (:) => { tt2ts!(Punct::new(':', Spacing::Alone)) }; - (|) => { tt2ts!(Punct::new('|', Spacing::Alone)) }; +use {Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +macro_rules! quote_tt { + (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; + ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; + ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; + (,) => { Punct::new(',', Spacing::Alone) }; + (.) => { Punct::new('.', Spacing::Alone) }; + (:) => { Punct::new(':', Spacing::Alone) }; + (;) => { Punct::new(';', Spacing::Alone) }; + (!) => { Punct::new('!', Spacing::Alone) }; + (<) => { Punct::new('<', Spacing::Alone) }; + (>) => { Punct::new('>', Spacing::Alone) }; + (&) => { Punct::new('&', Spacing::Alone) }; + (=) => { Punct::new('=', Spacing::Alone) }; + ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; +} + +macro_rules! quote_ts { + ((@ $($t:tt)*)) => { $($t)* }; (::) => { [ TokenTree::from(Punct::new(':', Spacing::Joint)), @@ -55,65 +46,45 @@ macro_rules! quote_tok { }) .collect::<TokenStream>() }; - (!) => { tt2ts!(Punct::new('!', Spacing::Alone)) }; - (<) => { tt2ts!(Punct::new('<', Spacing::Alone)) }; - (>) => { tt2ts!(Punct::new('>', Spacing::Alone)) }; - (_) => { tt2ts!(Punct::new('_', Spacing::Alone)) }; - (0) => { tt2ts!(Literal::i8_unsuffixed(0)) }; - (&) => { tt2ts!(Punct::new('&', Spacing::Alone)) }; - ($i:ident) => { tt2ts!(Ident::new(stringify!($i), Span::def_site())) }; -} - -macro_rules! quote_tree { - ((unquote $($t:tt)*)) => { $($t)* }; - ((quote $($t:tt)*)) => { ($($t)*).quote() }; - (($($t:tt)*)) => { tt2ts!(Group::new(Delimiter::Parenthesis, quote!($($t)*))) }; - ([$($t:tt)*]) => { tt2ts!(Group::new(Delimiter::Bracket, quote!($($t)*))) }; - ({$($t:tt)*}) => { tt2ts!(Group::new(Delimiter::Brace, quote!($($t)*))) }; - ($t:tt) => { quote_tok!($t) }; + ($t:tt) => { TokenTree::from(quote_tt!($t)) }; } +/// Simpler version of the real `quote!` macro, implemented solely +/// through `macro_rules`, for bootstrapping the real implementation +/// (see the `quote` function), which does not have access to the +/// real `quote!` macro due to the `proc_macro` crate not being +/// able to depend on itself. +/// +/// Note: supported tokens are a subset of the real `quote!`, but +/// unquoting is different: instead of `$x`, this uses `(@ expr)`. macro_rules! quote { () => { TokenStream::new() }; ($($t:tt)*) => { - [$(quote_tree!($t),)*].iter() - .cloned() - .flat_map(|x| x.into_iter()) - .collect::<TokenStream>() + [ + $(TokenStream::from(quote_ts!($t)),)* + ].iter().cloned().collect::<TokenStream>() }; } -impl ProcMacro for Quoter { - fn expand<'cx>(&self, cx: &'cx mut ExtCtxt, - _: ::syntax_pos::Span, - stream: tokenstream::TokenStream) - -> tokenstream::TokenStream { - ::__internal::set_sess(cx, || TokenStream(stream).quote().0) - } -} - -impl<T: Quote> Quote for Option<T> { - fn quote(self) -> TokenStream { - match self { - Some(t) => quote!(Some((quote t))), - None => quote!(None), - } +/// Quote a `TokenStream` into a `TokenStream`. +/// This is the actual `quote!()` proc macro. +/// +/// It is manually loaded in `CStore::load_macro_untracked`. +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub fn quote(stream: TokenStream) -> TokenStream { + if stream.is_empty() { + return quote!(::TokenStream::new()); } -} - -impl Quote for TokenStream { - fn quote(self) -> TokenStream { - if self.is_empty() { - return quote!(::TokenStream::new()); - } - let mut after_dollar = false; - let tokens = self.into_iter().filter_map(|tree| { + let mut after_dollar = false; + let tokens = stream + .into_iter() + .filter_map(|tree| { if after_dollar { after_dollar = false; match tree { TokenTree::Ident(_) => { - let tree = TokenStream::from(tree); - return Some(quote!(::__internal::unquote(&(unquote tree)),)); + return Some(quote!(Into::<::TokenStream>::into( + Clone::clone(&(@ tree))),)); } TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), @@ -125,186 +96,55 @@ impl Quote for TokenStream { } } - Some(quote!(::TokenStream::from((quote tree)),)) - }).flat_map(|t| t.into_iter()).collect::<TokenStream>(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!( - [(unquote tokens)].iter() - .cloned() - .flat_map(|x| x.into_iter()) - .collect::<::TokenStream>() - ) - } -} - -impl Quote for TokenTree { - fn quote(self) -> TokenStream { - match self { - TokenTree::Punct(tt) => quote!(::TokenTree::Punct( (quote tt) )), - TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )), - TokenTree::Ident(tt) => quote!(::TokenTree::Ident( (quote tt) )), - TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )), - } - } -} - -impl Quote for char { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::character(self)).into() - } -} - -impl<'a> Quote for &'a str { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::string(self)).into() - } -} - -impl Quote for u16 { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::u16_unsuffixed(self)).into() - } -} - -impl Quote for Group { - fn quote(self) -> TokenStream { - quote!(::Group::new((quote self.delimiter()), (quote self.stream()))) - } -} - -impl Quote for Punct { - fn quote(self) -> TokenStream { - quote!(::Punct::new((quote self.as_char()), (quote self.spacing()))) - } -} - -impl Quote for Ident { - fn quote(self) -> TokenStream { - quote!(::Ident::new((quote self.sym.as_str()), (quote self.span()))) - } -} - -impl Quote for Span { - fn quote(self) -> TokenStream { - quote!(::Span::def_site()) - } -} - -macro_rules! literals { - ($($i:ident),*; $($raw:ident),*) => { - pub struct SpannedSymbol { - sym: Symbol, - span: Span, - } - - impl SpannedSymbol { - pub fn new(string: &str, span: Span) -> SpannedSymbol { - SpannedSymbol { sym: Symbol::intern(string), span } - } - } - - impl Quote for SpannedSymbol { - fn quote(self) -> TokenStream { - quote!(::__internal::SpannedSymbol::new((quote self.sym.as_str()), - (quote self.span))) - } - } - - pub enum LiteralKind { - $($i,)* - $($raw(u16),)* - } - - impl LiteralKind { - pub fn with_contents_and_suffix(self, contents: SpannedSymbol, - suffix: Option<SpannedSymbol>) -> Literal { - let sym = contents.sym; - let suffix = suffix.map(|t| t.sym); - match self { - $(LiteralKind::$i => { - Literal { - lit: token::Lit::$i(sym), - suffix, - span: contents.span, - } - })* - $(LiteralKind::$raw(n) => { - Literal { - lit: token::Lit::$raw(sym, n), - suffix, - span: contents.span, - } - })* - } - } - } - - impl Literal { - fn kind_contents_and_suffix(self) -> (LiteralKind, SpannedSymbol, Option<SpannedSymbol>) - { - let (kind, contents) = match self.lit { - $(token::Lit::$i(contents) => (LiteralKind::$i, contents),)* - $(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)* - }; - let suffix = self.suffix.map(|sym| SpannedSymbol::new(&sym.as_str(), self.span())); - (kind, SpannedSymbol::new(&contents.as_str(), self.span()), suffix) - } - } - - impl Quote for LiteralKind { - fn quote(self) -> TokenStream { - match self { - $(LiteralKind::$i => quote! { - ::__internal::LiteralKind::$i - },)* - $(LiteralKind::$raw(n) => quote! { - ::__internal::LiteralKind::$raw((quote n)) - },)* - } - } - } + Some(quote!(::TokenStream::from((@ match tree { + TokenTree::Punct(tt) => quote!(::TokenTree::Punct(::Punct::new( + (@ TokenTree::from(Literal::character(tt.as_char()))), + (@ match tt.spacing() { + Spacing::Alone => quote!(::Spacing::Alone), + Spacing::Joint => quote!(::Spacing::Joint), + }), + ))), + TokenTree::Group(tt) => quote!(::TokenTree::Group(::Group::new( + (@ match tt.delimiter() { + Delimiter::Parenthesis => quote!(::Delimiter::Parenthesis), + Delimiter::Brace => quote!(::Delimiter::Brace), + Delimiter::Bracket => quote!(::Delimiter::Bracket), + Delimiter::None => quote!(::Delimiter::None), + }), + (@ quote(tt.stream())), + ))), + TokenTree::Ident(tt) => quote!(::TokenTree::Ident(::Ident::new( + (@ TokenTree::from(Literal::string(&tt.to_string()))), + (@ quote_span(tt.span())), + ))), + TokenTree::Literal(tt) => quote!(::TokenTree::Literal({ + let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) + .parse::<::TokenStream>() + .unwrap() + .into_iter(); + if let (Some(::TokenTree::Literal(mut lit)), None) = + (iter.next(), iter.next()) + { + lit.set_span((@ quote_span(tt.span()))); + lit + } else { + unreachable!() + } + })) + })),)) + }) + .collect::<TokenStream>(); - impl Quote for Literal { - fn quote(self) -> TokenStream { - let (kind, contents, suffix) = self.kind_contents_and_suffix(); - quote! { - (quote kind).with_contents_and_suffix((quote contents), (quote suffix)) - } - } - } + if after_dollar { + panic!("unexpected trailing `$` in `quote!`"); } -} -literals!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw); - -impl Quote for Delimiter { - fn quote(self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match self { - $(Delimiter::$i => { quote!(::Delimiter::$i) })* - } - } - } - - gen_match!(Parenthesis, Brace, Bracket, None) - } + quote!([(@ tokens)].iter().cloned().collect::<::TokenStream>()) } -impl Quote for Spacing { - fn quote(self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match self { - $(Spacing::$i => { quote!(::Spacing::$i) })* - } - } - } - - gen_match!(Alone, Joint) - } +/// Quote a `Span` into a `TokenStream`. +/// This is needed to implement a custom quoter. +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub fn quote_span(_: Span) -> TokenStream { + quote!(::Span::def_site()) } diff --git a/src/libproc_macro/rustc.rs b/src/libproc_macro/rustc.rs new file mode 100644 index 00000000000..a54c695f637 --- /dev/null +++ b/src/libproc_macro/rustc.rs @@ -0,0 +1,284 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use {Delimiter, Level, Spacing, Span, __internal}; +use {Group, Ident, Literal, Punct, TokenTree}; + +use rustc_errors as errors; +use syntax::ast; +use syntax::parse::lexer::comments; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::symbol::{keywords, Symbol}; + +impl Ident { + pub(crate) fn new_maybe_raw(string: &str, span: Span, is_raw: bool) -> Ident { + let sym = Symbol::intern(string); + if is_raw + && (sym == keywords::Underscore.name() + || ast::Ident::with_empty_ctxt(sym).is_path_segment_keyword()) + { + panic!("`{:?}` is not a valid raw identifier", string) + } + Ident { sym, span, is_raw } + } +} + +impl Delimiter { + pub(crate) fn from_internal(delim: token::DelimToken) -> Delimiter { + match delim { + token::Paren => Delimiter::Parenthesis, + token::Brace => Delimiter::Brace, + token::Bracket => Delimiter::Bracket, + token::NoDelim => Delimiter::None, + } + } + + pub(crate) fn to_internal(self) -> token::DelimToken { + match self { + Delimiter::Parenthesis => token::Paren, + Delimiter::Brace => token::Brace, + Delimiter::Bracket => token::Bracket, + Delimiter::None => token::NoDelim, + } + } +} + +impl TokenTree { + pub(crate) fn from_internal( + stream: tokenstream::TokenStream, + stack: &mut Vec<TokenTree>, + ) -> TokenTree { + use syntax::parse::token::*; + + let (tree, is_joint) = stream.as_tree(); + let (span, token) = match tree { + tokenstream::TokenTree::Token(span, token) => (span, token), + tokenstream::TokenTree::Delimited(span, delimed) => { + let delimiter = Delimiter::from_internal(delimed.delim); + let mut g = Group::new(delimiter, ::TokenStream(delimed.tts.into())); + g.set_span(Span(span)); + return g.into(); + } + }; + + let op_kind = if is_joint { + Spacing::Joint + } else { + Spacing::Alone + }; + macro_rules! tt { + ($e:expr) => {{ + let mut x = TokenTree::from($e); + x.set_span(Span(span)); + x + }}; + } + macro_rules! op { + ($a:expr) => { + tt!(Punct::new($a, op_kind)) + }; + ($a:expr, $b:expr) => {{ + stack.push(tt!(Punct::new($b, op_kind))); + tt!(Punct::new($a, Spacing::Joint)) + }}; + ($a:expr, $b:expr, $c:expr) => {{ + stack.push(tt!(Punct::new($c, op_kind))); + stack.push(tt!(Punct::new($b, Spacing::Joint))); + tt!(Punct::new($a, Spacing::Joint)) + }}; + } + + match token { + Eq => op!('='), + Lt => op!('<'), + Le => op!('<', '='), + EqEq => op!('=', '='), + Ne => op!('!', '='), + Ge => op!('>', '='), + Gt => op!('>'), + AndAnd => op!('&', '&'), + OrOr => op!('|', '|'), + Not => op!('!'), + Tilde => op!('~'), + BinOp(Plus) => op!('+'), + BinOp(Minus) => op!('-'), + BinOp(Star) => op!('*'), + BinOp(Slash) => op!('/'), + BinOp(Percent) => op!('%'), + BinOp(Caret) => op!('^'), + BinOp(And) => op!('&'), + BinOp(Or) => op!('|'), + BinOp(Shl) => op!('<', '<'), + BinOp(Shr) => op!('>', '>'), + BinOpEq(Plus) => op!('+', '='), + BinOpEq(Minus) => op!('-', '='), + BinOpEq(Star) => op!('*', '='), + BinOpEq(Slash) => op!('/', '='), + BinOpEq(Percent) => op!('%', '='), + BinOpEq(Caret) => op!('^', '='), + BinOpEq(And) => op!('&', '='), + BinOpEq(Or) => op!('|', '='), + BinOpEq(Shl) => op!('<', '<', '='), + BinOpEq(Shr) => op!('>', '>', '='), + At => op!('@'), + Dot => op!('.'), + DotDot => op!('.', '.'), + DotDotDot => op!('.', '.', '.'), + DotDotEq => op!('.', '.', '='), + Comma => op!(','), + Semi => op!(';'), + Colon => op!(':'), + ModSep => op!(':', ':'), + RArrow => op!('-', '>'), + LArrow => op!('<', '-'), + FatArrow => op!('=', '>'), + Pound => op!('#'), + Dollar => op!('$'), + Question => op!('?'), + SingleQuote => op!('\''), + + Ident(ident, false) => tt!(self::Ident::new(&ident.as_str(), Span(span))), + Ident(ident, true) => tt!(self::Ident::new_raw(&ident.as_str(), Span(span))), + Lifetime(ident) => { + let ident = ident.without_first_quote(); + stack.push(tt!(self::Ident::new(&ident.as_str(), Span(span)))); + tt!(Punct::new('\'', Spacing::Joint)) + } + Literal(lit, suffix) => tt!(self::Literal { + lit, + suffix, + span: Span(span) + }), + DocComment(c) => { + let style = comments::doc_comment_style(&c.as_str()); + let stripped = comments::strip_doc_comment_decoration(&c.as_str()); + let stream = vec![ + tt!(self::Ident::new("doc", Span(span))), + tt!(Punct::new('=', Spacing::Alone)), + tt!(self::Literal::string(&stripped)), + ].into_iter() + .collect(); + stack.push(tt!(Group::new(Delimiter::Bracket, stream))); + if style == ast::AttrStyle::Inner { + stack.push(tt!(Punct::new('!', Spacing::Alone))); + } + tt!(Punct::new('#', Spacing::Alone)) + } + + Interpolated(_) => __internal::with_sess(|sess, _| { + let tts = token.interpolated_to_tokenstream(sess, span); + tt!(Group::new(Delimiter::None, ::TokenStream(tts))) + }), + + DotEq => op!('.', '='), + OpenDelim(..) | CloseDelim(..) => unreachable!(), + Whitespace | Comment | Shebang(..) | Eof => unreachable!(), + } + } + + pub(crate) fn to_internal(self) -> tokenstream::TokenStream { + use syntax::parse::token::*; + use syntax::tokenstream::{Delimited, TokenTree}; + + let (ch, kind, span) = match self { + self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()), + self::TokenTree::Group(tt) => { + return TokenTree::Delimited( + tt.span.0, + Delimited { + delim: tt.delimiter.to_internal(), + tts: tt.stream.0.into(), + }, + ).into(); + } + self::TokenTree::Ident(tt) => { + let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw); + return TokenTree::Token(tt.span.0, token).into(); + } + self::TokenTree::Literal(self::Literal { + lit: Lit::Integer(ref a), + suffix, + span, + }) + if a.as_str().starts_with("-") => + { + let minus = BinOp(BinOpToken::Minus); + let integer = Symbol::intern(&a.as_str()[1..]); + let integer = Literal(Lit::Integer(integer), suffix); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, integer); + return vec![a, b].into_iter().collect(); + } + self::TokenTree::Literal(self::Literal { + lit: Lit::Float(ref a), + suffix, + span, + }) + if a.as_str().starts_with("-") => + { + let minus = BinOp(BinOpToken::Minus); + let float = Symbol::intern(&a.as_str()[1..]); + let float = Literal(Lit::Float(float), suffix); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, float); + return vec![a, b].into_iter().collect(); + } + self::TokenTree::Literal(tt) => { + let token = Literal(tt.lit, tt.suffix); + return TokenTree::Token(tt.span.0, token).into(); + } + }; + + let token = match ch { + '=' => Eq, + '<' => Lt, + '>' => Gt, + '!' => Not, + '~' => Tilde, + '+' => BinOp(Plus), + '-' => BinOp(Minus), + '*' => BinOp(Star), + '/' => BinOp(Slash), + '%' => BinOp(Percent), + '^' => BinOp(Caret), + '&' => BinOp(And), + '|' => BinOp(Or), + '@' => At, + '.' => Dot, + ',' => Comma, + ';' => Semi, + ':' => Colon, + '#' => Pound, + '$' => Dollar, + '?' => Question, + '\'' => SingleQuote, + _ => unreachable!(), + }; + + let tree = TokenTree::Token(span.0, token); + match kind { + Spacing::Alone => tree.into(), + Spacing::Joint => tree.joint(), + } + } +} + +impl Level { + pub(crate) fn to_internal(self) -> errors::Level { + match self { + Level::Error => errors::Level::Error, + Level::Warning => errors::Level::Warning, + Level::Note => errors::Level::Note, + Level::Help => errors::Level::Help, + Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive"), + } + } +} diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 5a595d14db7..f2f7f95426a 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -51,6 +51,12 @@ impl MaybeFnLike for ast::Item { } } +impl MaybeFnLike for ast::ImplItem { + fn is_fn_like(&self) -> bool { + match self.node { ast::ImplItemKind::Method(..) => true, _ => false, } + } +} + impl MaybeFnLike for ast::TraitItem { fn is_fn_like(&self) -> bool { match self.node { @@ -141,7 +147,7 @@ impl<'a> FnLikeNode<'a> { let fn_like = match node { map::NodeItem(item) => item.is_fn_like(), map::NodeTraitItem(tm) => tm.is_fn_like(), - map::NodeImplItem(_) => true, + map::NodeImplItem(it) => it.is_fn_like(), map::NodeExpr(e) => e.is_fn_like(), _ => false }; diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 5b5ae6473f8..9283705b7b7 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -562,36 +562,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> { - let mut variables = Vec::new(); - - { - let mut type_variables = self.type_variables.borrow_mut(); - variables.extend( - type_variables - .unsolved_variables() - .into_iter() - .map(|t| self.tcx.mk_var(t))); - } - - { - let mut int_unification_table = self.int_unification_table.borrow_mut(); - variables.extend( + let mut type_variables = self.type_variables.borrow_mut(); + let mut int_unification_table = self.int_unification_table.borrow_mut(); + let mut float_unification_table = self.float_unification_table.borrow_mut(); + + type_variables + .unsolved_variables() + .into_iter() + .map(|t| self.tcx.mk_var(t)) + .chain( (0..int_unification_table.len()) .map(|i| ty::IntVid { index: i as u32 }) .filter(|&vid| int_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_int_var(v))); - } - - { - let mut float_unification_table = self.float_unification_table.borrow_mut(); - variables.extend( + .map(|v| self.tcx.mk_int_var(v)) + ).chain( (0..float_unification_table.len()) .map(|i| ty::FloatVid { index: i as u32 }) .filter(|&vid| float_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_float_var(v))); - } - - return variables; + .map(|v| self.tcx.mk_float_var(v)) + ).collect() } fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a46b3120622..0ab10bf223f 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -77,7 +77,8 @@ declare_lint! { declare_lint! { pub UNREACHABLE_CODE, Warn, - "detects unreachable code paths" + "detects unreachable code paths", + report_in_external_macro: true } declare_lint! { @@ -216,7 +217,8 @@ declare_lint! { declare_lint! { pub DEPRECATED, Warn, - "detects use of deprecated items" + "detects use of deprecated items", + report_in_external_macro: true } declare_lint! { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 8efce297a91..c0f3c351d26 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -39,7 +39,7 @@ use hir::intravisit; use hir; use lint::builtin::BuiltinLintDiagnostics; use session::{Session, DiagnosticMessageId}; -use std::hash; +use std::{hash, ptr}; use syntax::ast; use syntax::codemap::{MultiSpan, ExpnFormat}; use syntax::edition::Edition; @@ -80,6 +80,9 @@ pub struct Lint { /// Starting at the given edition, default to the given lint level. If this is `None`, then use /// `default_level`. pub edition_lint_opts: Option<(Edition, Level)>, + + /// Whether this lint is reported even inside expansions of external macros + pub report_in_external_macro: bool, } impl Lint { @@ -100,11 +103,18 @@ impl Lint { #[macro_export] macro_rules! declare_lint { ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( + declare_lint!{$vis $NAME, $Level, $desc, false} + ); + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, report_in_external_macro: $rep: expr) => ( + declare_lint!{$vis $NAME, $Level, $desc, $rep} + ); + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $external: expr) => ( $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, desc: $desc, edition_lint_opts: None, + report_in_external_macro: $external, }; ); ($vis: vis $NAME: ident, $Level: ident, $desc: expr, @@ -115,6 +125,7 @@ macro_rules! declare_lint { default_level: $crate::lint::$Level, desc: $desc, edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)), + report_in_external_macro: false, }; ); } @@ -354,7 +365,7 @@ pub struct LintId { impl PartialEq for LintId { fn eq(&self, other: &LintId) -> bool { - (self.lint as *const Lint) == (other.lint as *const Lint) + ptr::eq(self.lint, other.lint) } } @@ -583,8 +594,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session, // items to take care of (delete the macro invocation). As a result we have // a few lints we whitelist here for allowing a lint even though it's in a // foreign macro invocation. - } else if lint_id != LintId::of(builtin::UNREACHABLE_CODE) && - lint_id != LintId::of(builtin::DEPRECATED) { + } else if !lint.report_in_external_macro { if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { err.cancel(); } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 60b47dbbd19..e4fc1b09fce 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -391,16 +391,12 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels, krate: &hir::Crate) - -> Vec<ast::NodeId> { - let mut worklist = Vec::new(); - for (id, _) in &access_levels.map { - worklist.push(*id); - } - - // Seed entry point - if let Some((id, _, _)) = *tcx.sess.entry_fn.borrow() { - worklist.push(id); - } + -> Vec<ast::NodeId> +{ + let worklist = access_levels.map.iter().map(|(&id, _)| id).chain( + // Seed entry point + tcx.sess.entry_fn.borrow().map(|(id, _, _)| id) + ).collect::<Vec<_>>(); // Seed implemented trait items let mut life_seeder = LifeSeeder { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 178f0d3cdcb..bd24b93f029 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -47,7 +47,7 @@ use std::ops::Deref; use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; use std::slice; use std::vec::IntoIter; -use std::mem; +use std::{mem, ptr}; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; @@ -527,8 +527,7 @@ impl<'tcx> PartialOrd for TyS<'tcx> { impl<'tcx> PartialEq for TyS<'tcx> { #[inline] fn eq(&self, other: &TyS<'tcx>) -> bool { - // (self as *const _) == (other as *const _) - (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>) + ptr::eq(self, other) } } impl<'tcx> Eq for TyS<'tcx> {} @@ -678,7 +677,7 @@ impl<T> PartialOrd for Slice<T> where T: PartialOrd { impl<T: PartialEq> PartialEq for Slice<T> { #[inline] fn eq(&self, other: &Slice<T>) -> bool { - (self as *const _) == (other as *const _) + ptr::eq(self, other) } } impl<T: Eq> Eq for Slice<T> {} @@ -1730,7 +1729,7 @@ impl Ord for AdtDef { impl PartialEq for AdtDef { // AdtDef are always interned and this is part of TyS equality #[inline] - fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } + fn eq(&self, other: &Self) -> bool { ptr::eq(self, other) } } impl Eq for AdtDef {} diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index a54deeca293..56a8c13a8d3 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -20,7 +20,7 @@ use ty::query::plumbing::CycleError; use ty::context::TyCtxt; use errors::Diagnostic; use std::process; -use std::fmt; +use std::{fmt, ptr}; use std::collections::HashSet; #[cfg(parallel_queries)] use { @@ -124,7 +124,7 @@ impl<'tcx> QueryJob<'tcx> { while let Some(job) = current_job { cycle.insert(0, job.info.clone()); - if &*job as *const _ == self as *const _ { + if ptr::eq(&*job, self) { // This is the end of the cycle // The span entry we included was for the usage // of the cycle itself, and not part of the cycle diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index b1502902079..f1a6e9913d6 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -565,7 +565,13 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { } fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { - let mut llargument_tys = Vec::new(); + let args_capacity: usize = self.args.iter().map(|arg| + if arg.pad.is_some() { 1 } else { 0 } + + if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 } + ).sum(); + let mut llargument_tys = Vec::with_capacity( + if let PassMode::Indirect(_) = self.ret.mode { 1 } else { 0 } + args_capacity + ); let llreturn_ty = match self.ret.mode { PassMode::Ignore => Type::void(cx), diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index a33f8b569d0..60b5cf2ec76 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -759,20 +759,6 @@ impl ThinModule { cgcx.save_temp_bitcode(&module, "thin-lto-after-pm"); timeline.record("thin-done"); - // FIXME: this is a hack around a bug in LLVM right now. Discovered in - // #46910 it was found out that on 32-bit MSVC LLVM will hit a codegen - // error if there's an available_externally function in the LLVM module. - // Typically we don't actually use these functions but ThinLTO makes - // heavy use of them when inlining across modules. - // - // Tracked upstream at https://bugs.llvm.org/show_bug.cgi?id=35736 this - // function call (and its definition on the C++ side of things) - // shouldn't be necessary eventually and we can safetly delete these few - // lines. - llvm::LLVMRustThinLTORemoveAvailableExternally(llmod); - cgcx.save_temp_bitcode(&module, "thin-lto-after-rm-ae"); - timeline.record("no-ae"); - Ok(module) } } diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index c71e49b0d88..e4acb2ad4b1 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -13,7 +13,7 @@ use llvm; use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef}; -use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; +use llvm::{ValueRef, BasicBlockRef, BuilderRef}; use common::*; use type_::Type; use value::Value; @@ -1157,23 +1157,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn trap(&self) { - unsafe { - let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); - let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); - let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); - let p = "llvm.trap\0".as_ptr(); - let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); - assert!((t as isize != 0)); - let args: &[ValueRef] = &[]; - self.count_insn("trap"); - llvm::LLVMRustBuildCall(self.llbuilder, t, - args.as_ptr(), args.len() as c_uint, - ptr::null_mut(), - noname()); - } - } - pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef, num_clauses: usize) -> ValueRef { self.count_insn("landingpad"); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index b386f887d77..ef0d57c7b7c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -56,29 +56,30 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; -pub mod array_vec; pub mod accumulate_vec; -pub mod small_vec; +pub mod array_vec; pub mod base_n; pub mod bitslice; pub mod bitvec; +pub mod flock; +pub mod fx; +pub mod graph; pub mod indexed_set; pub mod indexed_vec; pub mod obligation_forest; +pub mod owning_ref; +pub mod ptr_key; pub mod sip128; +pub mod small_vec; pub mod snapshot_map; pub use ena::snapshot_vec; +pub mod sorted_map; pub mod stable_hasher; -pub mod transitive_relation; -pub use ena::unify; -pub mod fx; -pub mod tuple_slice; -pub mod graph; -pub mod flock; pub mod sync; -pub mod owning_ref; pub mod tiny_list; -pub mod sorted_map; +pub mod transitive_relation; +pub mod tuple_slice; +pub use ena::unify; pub mod work_queue; pub struct OnDrop<F: Fn()>(pub F); diff --git a/src/librustc_data_structures/ptr_key.rs b/src/librustc_data_structures/ptr_key.rs new file mode 100644 index 00000000000..6835dab38df --- /dev/null +++ b/src/librustc_data_structures/ptr_key.rs @@ -0,0 +1,45 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{hash, ptr}; +use std::ops::Deref; + +/// A wrapper around reference that compares and hashes like a pointer. +/// Can be used as a key in sets/maps indexed by pointers to avoid `unsafe`. +#[derive(Debug)] +pub struct PtrKey<'a, T: 'a>(pub &'a T); + +impl<'a, T> Clone for PtrKey<'a, T> { + fn clone(&self) -> Self { *self } +} + +impl<'a, T> Copy for PtrKey<'a, T> {} + +impl<'a, T> PartialEq for PtrKey<'a, T> { + fn eq(&self, rhs: &Self) -> bool { + ptr::eq(self.0, rhs.0) + } +} + +impl<'a, T> Eq for PtrKey<'a, T> {} + +impl<'a, T> hash::Hash for PtrKey<'a, T> { + fn hash<H: hash::Hasher>(&self, hasher: &mut H) { + (self.0 as *const T).hash(hasher) + } +} + +impl<'a, T> Deref for PtrKey<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0 + } +} diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index d079102a4ba..b1578b697bb 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -379,7 +379,7 @@ impl Diagnostic { /// Convenience function for internal use, clients should use one of the /// public methods above. - pub(crate) fn sub(&mut self, + pub fn sub(&mut self, level: Level, message: &str, span: MultiSpan, diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index b4483557dd3..8d04438eea2 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1791,7 +1791,6 @@ extern "C" { CU1: *mut *mut c_void, CU2: *mut *mut c_void); pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void); - pub fn LLVMRustThinLTORemoveAvailableExternally(M: ModuleRef); pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef; pub fn LLVMRustLinkerAdd(linker: LinkerRef, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d5078642147..e3a7918f8c5 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -39,7 +39,6 @@ use syntax::ast; use syntax::attr; use syntax::codemap; use syntax::edition::Edition; -use syntax::ext::base::SyntaxExtension; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; use syntax_pos::{Span, NO_EXPANSION, FileName}; @@ -517,8 +516,11 @@ impl CrateStore for cstore::CStore { return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone()); } else if data.name == "proc_macro" && self.get_crate_data(id.krate).item_name(id.index) == "quote" { + use syntax::ext::base::SyntaxExtension; + use syntax_ext::proc_macro_impl::BangProcMacro; + let ext = SyntaxExtension::ProcMacro { - expander: Box::new(::proc_macro::__internal::Quoter), + expander: Box::new(BangProcMacro { inner: ::proc_macro::quote }), allow_internal_unstable: true, edition: data.root.edition, }; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 5c9915e94e5..d535c1ef903 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -19,6 +19,7 @@ #![feature(libc)] #![feature(macro_at_most_once_rep)] #![feature(proc_macro_internals)] +#![feature(proc_macro_quote)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index e00919547fc..da2847dc557 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -651,7 +651,7 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, span: Span, allow_shadowing: bool) { - if self.global_macros.insert(name, binding).is_some() && !allow_shadowing { + if self.macro_prelude.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; @@ -704,8 +704,7 @@ impl<'a> Resolver<'a> { } else { for (name, span) in legacy_imports.imports { let ident = Ident::with_empty_ctxt(name); - let result = self.resolve_ident_in_module(module, ident, MacroNS, - false, false, span); + let result = self.resolve_ident_in_module(module, ident, MacroNS, false, span); if let Ok(binding) = result { let directive = macro_use_directive(span); self.potentially_unused_imports.push(directive); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d98434796d5..9fe25aaa6c0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1393,7 +1393,7 @@ pub struct Resolver<'a> { crate_loader: &'a mut dyn CrateLoader, macro_names: FxHashSet<Ident>, - global_macros: FxHashMap<Name, &'a NameBinding<'a>>, + macro_prelude: FxHashMap<Name, &'a NameBinding<'a>>, pub all_macros: FxHashMap<Name, Def>, lexical_macro_resolutions: Vec<(Ident, &'a Cell<LegacyScope<'a>>)>, macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>, @@ -1715,7 +1715,7 @@ impl<'a> Resolver<'a> { crate_loader, macro_names: FxHashSet(), - global_macros: FxHashMap(), + macro_prelude: FxHashMap(), all_macros: FxHashMap(), lexical_macro_resolutions: Vec::new(), macro_map: FxHashMap(), @@ -2002,7 +2002,6 @@ impl<'a> Resolver<'a> { module: Module<'a>, mut ident: Ident, ns: Namespace, - ignore_unresolved_invocations: bool, record_used: bool, span: Span) -> Result<&'a NameBinding<'a>, Determinacy> { @@ -2012,7 +2011,7 @@ impl<'a> Resolver<'a> { self.current_module = self.macro_def_scope(def); } let result = self.resolve_ident_in_module_unadjusted( - module, ident, ns, ignore_unresolved_invocations, record_used, span, + module, ident, ns, false, record_used, span, ); self.current_module = orig_current_module; result @@ -2518,7 +2517,7 @@ impl<'a> Resolver<'a> { // If there is a TraitRef in scope for an impl, then the method must be in the // trait. if let Some((module, _)) = self.current_trait_ref { - if self.resolve_ident_in_module(module, ident, ns, false, false, span).is_err() { + if self.resolve_ident_in_module(module, ident, ns, false, span).is_err() { let path = &self.current_trait_ref.as_ref().unwrap().1.path; resolve_error(self, span, err(ident.name, &path_names_to_string(path))); } @@ -3225,7 +3224,7 @@ impl<'a> Resolver<'a> { }; } } - let is_global = self.global_macros.get(&path[0].name).cloned() + let is_global = self.macro_prelude.get(&path[0].name).cloned() .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false); if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].modern())) { @@ -3468,7 +3467,7 @@ impl<'a> Resolver<'a> { } let binding = if let Some(module) = module { - self.resolve_ident_in_module(module, ident, ns, false, record_used, path_span) + self.resolve_ident_in_module(module, ident, ns, record_used, path_span) } else if opt_ns == Some(MacroNS) { self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span) .map(MacroBinding::binding) @@ -3762,7 +3761,7 @@ impl<'a> Resolver<'a> { // Look for associated items in the current trait. if let Some((module, _)) = self.current_trait_ref { if let Ok(binding) = - self.resolve_ident_in_module(module, ident, ns, false, false, module.span) { + self.resolve_ident_in_module(module, ident, ns, false, module.span) { let def = binding.def(); if filter_fn(def) { return Some(if self.has_self.contains(&def.def_id()) { @@ -4075,7 +4074,7 @@ impl<'a> Resolver<'a> { let mut found_traits = Vec::new(); // Look for the current trait. if let Some((module, _)) = self.current_trait_ref { - if self.resolve_ident_in_module(module, ident, ns, false, false, module.span).is_ok() { + if self.resolve_ident_in_module(module, ident, ns, false, module.span).is_ok() { let def_id = module.def_id().unwrap(); found_traits.push(TraitCandidate { def_id: def_id, import_id: None }); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index f076d884f60..0ad652b4710 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -220,7 +220,7 @@ impl<'a> base::Resolver for Resolver<'a> { vis: ty::Visibility::Invisible, expansion: Mark::root(), }); - self.global_macros.insert(ident.name, binding); + self.macro_prelude.insert(ident.name, binding); } fn resolve_imports(&mut self) { @@ -238,7 +238,7 @@ impl<'a> base::Resolver for Resolver<'a> { attr::mark_known(&attrs[i]); } - match self.global_macros.get(&name).cloned() { + match self.macro_prelude.get(&name).cloned() { Some(binding) => match *binding.get_macro(self) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -274,7 +274,7 @@ impl<'a> base::Resolver for Resolver<'a> { } let trait_name = traits[j].segments[0].ident.name; let legacy_name = Symbol::intern(&format!("derive_{}", trait_name)); - if !self.global_macros.contains_key(&legacy_name) { + if !self.macro_prelude.contains_key(&legacy_name) { continue } let span = traits.remove(j).span; @@ -565,7 +565,7 @@ impl<'a> Resolver<'a> { module, ident, ns, true, record_used, path_span, ).map(MacroBinding::Modern) } else { - self.global_macros.get(&ident.name).cloned().ok_or(determinacy) + self.macro_prelude.get(&ident.name).cloned().ok_or(determinacy) .map(MacroBinding::Global) }; self.current_module = orig_current_module; @@ -588,8 +588,7 @@ impl<'a> Resolver<'a> { return potential_illegal_shadower; } } - if binding.expansion != Mark::root() || - (binding.is_glob_import() && module.unwrap().def().is_some()) { + if binding.is_glob_import() || binding.expansion != Mark::root() { potential_illegal_shadower = result; } else { return result; @@ -652,7 +651,7 @@ impl<'a> Resolver<'a> { let binding = if let Some(binding) = binding { MacroBinding::Legacy(binding) - } else if let Some(binding) = self.global_macros.get(&ident.name).cloned() { + } else if let Some(binding) = self.macro_prelude.get(&ident.name).cloned() { if !self.use_extern_macros { self.record_use(ident, MacroNS, binding, DUMMY_SP); } @@ -762,8 +761,8 @@ impl<'a> Resolver<'a> { // Then check global macros. }.or_else(|| { // FIXME: get_macro needs an &mut Resolver, can we do it without cloning? - let global_macros = self.global_macros.clone(); - let names = global_macros.iter().filter_map(|(name, binding)| { + let macro_prelude = self.macro_prelude.clone(); + let names = macro_prelude.iter().filter_map(|(name, binding)| { if binding.get_macro(self).kind() == kind { Some(name) } else { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 0ee17ebc487..50eb89be690 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -17,6 +17,7 @@ use Resolver; use {names_to_string, module_to_string}; use {resolve_error, ResolutionError}; +use rustc_data_structures::ptr_key::PtrKey; use rustc::ty; use rustc::lint::builtin::BuiltinLintDiagnostics; use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE}; @@ -104,67 +105,20 @@ impl<'a> ImportDirective<'a> { #[derive(Clone, Default, Debug)] /// Records information about the resolution of a name in a namespace of a module. pub struct NameResolution<'a> { - /// The single imports that define the name in the namespace. - single_imports: SingleImports<'a>, + /// Single imports that may define the name in the namespace. + /// Import directives are arena-allocated, so it's ok to use pointers as keys. + single_imports: FxHashSet<PtrKey<'a, ImportDirective<'a>>>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, - shadows_glob: Option<&'a NameBinding<'a>>, -} - -#[derive(Clone, Debug)] -enum SingleImports<'a> { - /// No single imports can define the name in the namespace. - None, - /// Only the given single import can define the name in the namespace. - MaybeOne(&'a ImportDirective<'a>), - /// Only one of these two single imports can define the name in the namespace. - MaybeTwo(&'a ImportDirective<'a>, &'a ImportDirective<'a>), - /// At least one single import will define the name in the namespace. - AtLeastOne, -} - -impl<'a> Default for SingleImports<'a> { - /// Creates a `SingleImports<'a>` of None type. - fn default() -> Self { - SingleImports::None - } -} - -impl<'a> SingleImports<'a> { - fn add_directive(&mut self, directive: &'a ImportDirective<'a>, use_extern_macros: bool) { - match *self { - SingleImports::None => *self = SingleImports::MaybeOne(directive), - SingleImports::MaybeOne(directive_one) => *self = if use_extern_macros { - SingleImports::MaybeTwo(directive_one, directive) - } else { - SingleImports::AtLeastOne - }, - // If three single imports can define the name in the namespace, we can assume that at - // least one of them will define it since otherwise we'd get duplicate errors in one of - // other namespaces. - SingleImports::MaybeTwo(..) => *self = SingleImports::AtLeastOne, - SingleImports::AtLeastOne => {} - }; - } - - fn directive_failed(&mut self, dir: &'a ImportDirective<'a>) { - match *self { - SingleImports::None => unreachable!(), - SingleImports::MaybeOne(_) => *self = SingleImports::None, - SingleImports::MaybeTwo(dir1, dir2) => - *self = SingleImports::MaybeOne(if ptr::eq(dir1, dir) { dir1 } else { dir2 }), - SingleImports::AtLeastOne => {} - } - } + shadowed_glob: Option<&'a NameBinding<'a>>, } impl<'a> NameResolution<'a> { // Returns the binding for the name if it is known or None if it not known. fn binding(&self) -> Option<&'a NameBinding<'a>> { - self.binding.and_then(|binding| match self.single_imports { - SingleImports::None => Some(binding), - _ if !binding.is_glob_import() => Some(binding), - _ => None, // The binding could be shadowed by a single import, so it is not known. + self.binding.and_then(|binding| { + if !binding.is_glob_import() || + self.single_imports.is_empty() { Some(binding) } else { None } }) } } @@ -177,7 +131,7 @@ impl<'a> Resolver<'a> { } /// Attempts to resolve `ident` in namespaces `ns` of `module`. - /// Invariant: if `record_used` is `Some`, import resolution must be complete. + /// Invariant: if `record_used` is `Some`, expansion and import resolution must be complete. pub fn resolve_ident_in_module_unadjusted(&mut self, module: Module<'a>, ident: Ident, @@ -194,7 +148,7 @@ impl<'a> Resolver<'a> { if record_used { if let Some(binding) = resolution.binding { - if let Some(shadowed_glob) = resolution.shadows_glob { + if let Some(shadowed_glob) = resolution.shadowed_glob { let name = ident.name; // Forbid expanded shadowing to avoid time travel. if restricted_shadowing && @@ -227,81 +181,72 @@ impl<'a> Resolver<'a> { if usable { Ok(binding) } else { Err(Determined) } }; - // Items and single imports are not shadowable. + // Items and single imports are not shadowable, if we have one, then it's determined. if let Some(binding) = resolution.binding { if !binding.is_glob_import() { return check_usable(self, binding); } } - // Check if a single import can still define the name. - let resolve_single_import = |this: &mut Self, directive: &'a ImportDirective<'a>| { - let module = match directive.imported_module.get() { - Some(module) => module, - None => return false, - }; - let ident = match directive.subclass { + // --- From now on we either have a glob resolution or no resolution. --- + + // Check if one of single imports can still define the name, + // if it can then our result is not determined and can be invalidated. + for single_import in &resolution.single_imports { + if !self.is_accessible(single_import.vis.get()) { + continue; + } + let module = unwrap_or!(single_import.imported_module.get(), return Err(Undetermined)); + let ident = match single_import.subclass { SingleImport { source, .. } => source, _ => unreachable!(), }; - match this.resolve_ident_in_module(module, ident, ns, false, false, path_span) { - Err(Determined) => {} - _ => return false, - } - true - }; - match resolution.single_imports { - SingleImports::AtLeastOne => return Err(Undetermined), - SingleImports::MaybeOne(directive) => { - let accessible = self.is_accessible(directive.vis.get()); - if accessible { - if !resolve_single_import(self, directive) { - return Err(Undetermined) - } - } - } - SingleImports::MaybeTwo(directive1, directive2) => { - let accessible1 = self.is_accessible(directive1.vis.get()); - let accessible2 = self.is_accessible(directive2.vis.get()); - if accessible1 && accessible2 { - if !resolve_single_import(self, directive1) && - !resolve_single_import(self, directive2) { - return Err(Undetermined) - } - } else if accessible1 { - if !resolve_single_import(self, directive1) { - return Err(Undetermined) - } - } else { - if !resolve_single_import(self, directive2) { - return Err(Undetermined) - } - } + match self.resolve_ident_in_module(module, ident, ns, false, path_span) { + Err(Determined) => continue, + Ok(_) | Err(Undetermined) => return Err(Undetermined), } - SingleImports::None => {}, } - let no_unresolved_invocations = - restricted_shadowing || module.unresolved_invocations.borrow().is_empty(); - match resolution.binding { - // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`). - Some(binding) if no_unresolved_invocations || ns == MacroNS => - return check_usable(self, binding), - None if no_unresolved_invocations => {} - _ => return Err(Undetermined), + // So we have a resolution that's from a glob import. This resolution is determined + // if it cannot be shadowed by some new item/import expanded from a macro. + // This happens either if there are no unexpanded macros, or expanded names cannot + // shadow globs (that happens in macro namespace or with restricted shadowing). + let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty(); + if let Some(binding) = resolution.binding { + if !unexpanded_macros || ns == MacroNS || restricted_shadowing { + return check_usable(self, binding); + } else { + return Err(Undetermined); + } } - // Check if the globs are determined - if restricted_shadowing && module.def().is_some() { + // --- From now on we have no resolution. --- + + // Now we are in situation when new item/import can appear only from a glob or a macro + // expansion. With restricted shadowing names from globs and macro expansions cannot + // shadow names from outer scopes, so we can freely fallback from module search to search + // in outer scopes. To continue search in outer scopes we have to lie a bit and return + // `Determined` to `resolve_lexical_macro_path_segment` even if the correct answer + // for in-module resolution could be `Undetermined`. + if restricted_shadowing { return Err(Determined); } - for directive in module.globs.borrow().iter() { - if !self.is_accessible(directive.vis.get()) { + + // Check if one of unexpanded macros can still define the name, + // if it can then our "no resolution" result is not determined and can be invalidated. + if unexpanded_macros { + return Err(Undetermined); + } + + // Check if one of glob imports can still define the name, + // if it can then our "no resolution" result is not determined and can be invalidated. + for glob_import in module.globs.borrow().iter() { + if !self.is_accessible(glob_import.vis.get()) { continue } - let module = unwrap_or!(directive.imported_module.get(), return Err(Undetermined)); + let module = unwrap_or!(glob_import.imported_module.get(), return Err(Undetermined)); let (orig_current_module, mut ident) = (self.current_module, ident.modern()); - match ident.span.glob_adjust(module.expansion, directive.span.ctxt().modern()) { + match ident.span.glob_adjust(module.expansion, glob_import.span.ctxt().modern()) { Some(Some(def)) => self.current_module = self.macro_def_scope(def), Some(None) => {} None => continue, @@ -310,11 +255,13 @@ impl<'a> Resolver<'a> { module, ident, ns, false, false, path_span, ); self.current_module = orig_current_module; - if let Err(Undetermined) = result { - return Err(Undetermined); + match result { + Err(Determined) => continue, + Ok(_) | Err(Undetermined) => return Err(Undetermined), } } + // No resolution and no one else can define the name - determinate error. Err(Determined) } @@ -348,7 +295,7 @@ impl<'a> Resolver<'a> { SingleImport { target, type_ns_only, .. } => { self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); - resolution.single_imports.add_directive(directive, this.use_extern_macros); + resolution.single_imports.insert(PtrKey(directive)); }); } // We don't add prelude imports to the globs since they only affect lexical scopes, @@ -401,7 +348,7 @@ impl<'a> Resolver<'a> { if binding.is_glob_import() { if !old_binding.is_glob_import() && !(ns == MacroNS && old_binding.expansion != Mark::root()) { - resolution.shadows_glob = Some(binding); + resolution.shadowed_glob = Some(binding); } else if binding.def() != old_binding.def() { resolution.binding = Some(this.ambiguity(old_binding, binding)); } else if !old_binding.vis.is_at_least(binding.vis, &*this) { @@ -414,7 +361,7 @@ impl<'a> Resolver<'a> { resolution.binding = Some(this.ambiguity(binding, old_binding)); } else { resolution.binding = Some(binding); - resolution.shadows_glob = Some(old_binding); + resolution.shadowed_glob = Some(old_binding); } } else { return Err(old_binding); @@ -455,7 +402,7 @@ impl<'a> Resolver<'a> { _ if 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, + Some(old_binding) if ptr::eq(old_binding, binding) => return t, _ => (binding, t), } } @@ -630,7 +577,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { source, ns, false, - false, directive.span)); } else { return @@ -641,7 +587,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Err(Undetermined) => indeterminate = true, Err(Determined) => { this.update_resolution(parent, target, ns, |_, resolution| { - resolution.single_imports.directive_failed(directive) + resolution.single_imports.remove(&PtrKey(directive)); }); } Ok(binding) if !binding.is_importable() => { @@ -803,7 +749,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if all_ns_err { let mut all_ns_failed = true; self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - match this.resolve_ident_in_module(module, ident, ns, false, true, span) { + match this.resolve_ident_in_module(module, ident, ns, true, span) { Ok(_) => all_ns_failed = false, _ => {} } @@ -827,7 +773,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => Some(&i.name), } }, - NameResolution { single_imports: SingleImports::None, .. } => None, + NameResolution { ref single_imports, .. } + if single_imports.is_empty() => None, _ => Some(&i.name), } }); @@ -973,7 +920,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let mut reexports = Vec::new(); let mut exported_macro_names = FxHashMap(); - if module as *const _ == self.graph_root as *const _ { + if ptr::eq(module, self.graph_root) { let macro_exports = mem::replace(&mut self.macro_exports, Vec::new()); for export in macro_exports.into_iter().rev() { if let Some(later_span) = exported_macro_names.insert(export.ident.modern(), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 465faa1d477..a2dbf2aaca3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1473,35 +1473,34 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>) -> Vec<ty::Predicate<'tcx>> { - let mut vec = Vec::new(); - // If it could be sized, and is, add the sized predicate - if self.implicitly_sized { - if let Some(sized) = tcx.lang_items().sized_trait() { + let sized_predicate = if self.implicitly_sized { + tcx.lang_items().sized_trait().map(|sized| { let trait_ref = ty::TraitRef { def_id: sized, substs: tcx.mk_substs_trait(param_ty, &[]) }; - vec.push(trait_ref.to_predicate()); - } - } - - 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 = tcx.mk_region(ty::fold::shift_region(*region_bound, 1)); - vec.push( - ty::Binder::dummy(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate()); - } - - for bound_trait_ref in &self.trait_bounds { - vec.push(bound_trait_ref.to_predicate()); - } - - for projection in &self.projection_bounds { - vec.push(projection.to_predicate()); - } + trait_ref.to_predicate() + }) + } else { + None + }; - vec + sized_predicate.into_iter().chain( + self.region_bounds.iter().map(|®ion_bound| { + // 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 = tcx.mk_region(ty::fold::shift_region(*region_bound, 1)); + ty::Binder::dummy(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate() + }).chain( + self.trait_bounds.iter().map(|bound_trait_ref| { + bound_trait_ref.to_predicate() + }) + ).chain( + self.projection_bounds.iter().map(|projection| { + projection.to_predicate() + }) + ) + ).collect() } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 089ecebbc9c..ae64c6f1bfd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -310,19 +310,19 @@ pub fn opts() -> Vec<RustcOptGroup> { "disable-minification", "Disable minification applied on JS files") }), - unstable("warn", |o| { + stable("warn", |o| { o.optmulti("W", "warn", "Set lint warnings", "OPT") }), - unstable("allow", |o| { + stable("allow", |o| { o.optmulti("A", "allow", "Set lint allowed", "OPT") }), - unstable("deny", |o| { + stable("deny", |o| { o.optmulti("D", "deny", "Set lint denied", "OPT") }), - unstable("forbid", |o| { + stable("forbid", |o| { o.optmulti("F", "forbid", "Set lint forbidden", "OPT") }), - unstable("cap-lints", |o| { + stable("cap-lints", |o| { o.optmulti( "", "cap-lints", diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fec14b8d67d..3c01de2e997 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -532,12 +532,8 @@ mod stdsimd; #[cfg(not(stage0))] mod coresimd { pub use core::arch; - pub use core::simd; } -#[unstable(feature = "stdsimd", issue = "48556")] -#[cfg(all(not(stage0), not(test)))] -pub use stdsimd::simd; #[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(all(not(stage0), not(test)))] pub use stdsimd::arch; diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1241e230b26..d64f3de8daa 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -240,6 +240,13 @@ impl Invocation { InvocationKind::Derive { ref path, .. } => path.span, } } + + pub fn attr_id(&self) -> Option<ast::AttrId> { + match self.kind { + InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id), + _ => None, + } + } } pub struct MacroExpander<'a, 'b:'a> { @@ -331,10 +338,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; + let attr_id_before = invoc.attr_id(); let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, Err(Determinacy::Undetermined) => { + // Sometimes attributes which we thought were invocations + // end up being custom attributes for custom derives. If + // that's the case our `invoc` will have changed out from + // under us. If this is the case we're making progress so we + // want to flag it as such, and we test this by looking if + // the `attr_id()` method has been changing over time. + if invoc.attr_id() != attr_id_before { + progress = true; + } undetermined_invocations.push(invoc); continue } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index bf790e6143a..9748e2947ee 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1775,12 +1775,6 @@ fn ident_continue(c: Option<char>) -> bool { (c > '\x7f' && c.is_xid_continue()) } -// The string is a valid identifier or a lifetime identifier. -pub fn is_valid_ident(s: &str) -> bool { - let mut chars = s.chars(); - ident_start(chars.next()) && chars.all(|ch| ident_continue(Some(ch))) -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index aef3beeccdf..fd8f394a600 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -777,11 +777,50 @@ fn prepend_attrs(sess: &ParseSess, for attr in attrs { assert_eq!(attr.style, ast::AttrStyle::Outer, "inner attributes should prevent cached tokens from existing"); - // FIXME: Avoid this pretty-print + reparse hack as bove - let name = FileName::MacroExpansion; - let source = pprust::attr_to_string(attr); - let stream = parse_stream_from_source_str(name, source, sess, Some(span)); - builder.push(stream); + + if attr.is_sugared_doc { + let stream = parse_stream_from_source_str( + FileName::MacroExpansion, + pprust::attr_to_string(attr), + sess, + Some(span), + ); + builder.push(stream); + continue + } + + // synthesize # [ $path $tokens ] manually here + let mut brackets = tokenstream::TokenStreamBuilder::new(); + + // For simple paths, push the identifier directly + if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() { + let ident = attr.path.segments[0].ident; + let token = Ident(ident, ident.as_str().starts_with("r#")); + brackets.push(tokenstream::TokenTree::Token(ident.span, token)); + + // ... and for more complicated paths, fall back to a reparse hack that + // should eventually be removed. + } else { + let stream = parse_stream_from_source_str( + FileName::MacroExpansion, + pprust::path_to_string(&attr.path), + sess, + Some(span), + ); + brackets.push(stream); + } + + brackets.push(attr.tokens.clone()); + + let tokens = tokenstream::Delimited { + delim: DelimToken::Bracket, + tts: brackets.build().into(), + }; + // The span we list here for `#` and for `[ ... ]` are both wrong in + // that it encompasses more than each token, but it hopefully is "good + // enough" for now at least. + builder.push(tokenstream::TokenTree::Token(attr.span, Pound)); + builder.push(tokenstream::TokenTree::Delimited(attr.span, tokens)); } builder.push(tokens.clone()); Some(builder.build()) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a00ff3b345d..2f28c5b32fb 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -1228,15 +1228,6 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { MD->addOperand(Unit); } -extern "C" void -LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { - Module *M = unwrap(Mod); - for (Function &F : M->functions()) { - if (F.hasAvailableExternallyLinkage()) - F.deleteBody(); - } -} - #else extern "C" bool @@ -1328,9 +1319,4 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod) { report_fatal_error("ThinLTO not available"); } -extern "C" void -LLVMRustThinLTORemoveAvailableExternally(LLVMModuleRef Mod) { - report_fatal_error("ThinLTO not available"); -} - #endif // LLVM_VERSION_GE(4, 0) diff --git a/src/stdsimd b/src/stdsimd -Subproject 886ff388fbbe8798e292431d824a5ff3c3458f4 +Subproject b9de11ab43090c71ff7ab159a479394df1f968a diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-two-attrs.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-two-attrs.rs new file mode 100644 index 00000000000..d02edb50fb2 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-two-attrs.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_derive(A, attributes(b))] +pub fn foo(_x: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-two-attrs.rs b/src/test/run-pass-fulldeps/proc-macro/derive-two-attrs.rs new file mode 100644 index 00000000000..6a0a3b3a941 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/derive-two-attrs.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-two-attrs.rs + +#![feature(use_extern_macros)] + +extern crate derive_two_attrs as foo; + +use foo::A; + +#[derive(A)] +#[b] +#[b] +struct B; + +fn main() {} diff --git a/src/test/run-pass/const-block.rs b/src/test/run-pass/const-block.rs index e56d01d7ba8..e6f191ea952 100644 --- a/src/test/run-pass/const-block.rs +++ b/src/test/run-pass/const-block.rs @@ -39,13 +39,6 @@ static BLOCK_FN: fn(usize) -> usize = { foo::<usize> }; static BLOCK_ENUM_CONSTRUCTOR: fn(usize) -> Option<usize> = { Some }; -// FIXME #13972 -// static BLOCK_UNSAFE_SAFE_PTR: &'static isize = unsafe { &*(0xdeadbeef as *const isize) }; -// static BLOCK_UNSAFE_SAFE_PTR_2: &'static isize = unsafe { -// const X: *const isize = 0xdeadbeef as *const isize; -// &*X -// }; - pub fn main() { assert_eq!(BLOCK_INTEGRAL, 1); assert_eq!(BLOCK_EXPLICIT_UNIT, ()); @@ -58,7 +51,4 @@ pub fn main() { assert_eq!(BLOCK_FN_INFERRED(300), 300); assert_eq!(BLOCK_FN(300), 300); assert_eq!(BLOCK_ENUM_CONSTRUCTOR(200), Some(200)); - // FIXME #13972 - // assert_eq!(BLOCK_UNSAFE_SAFE_PTR as *const isize as usize, 0xdeadbeef); - // assert_eq!(BLOCK_UNSAFE_SAFE_PTR_2 as *const isize as usize, 0xdeadbeef); } diff --git a/src/test/run-pass/sepcomp-lib-lto.rs b/src/test/run-pass/sepcomp-lib-lto.rs index f3e52fbd32f..8d73f4db7d2 100644 --- a/src/test/run-pass/sepcomp-lib-lto.rs +++ b/src/test/run-pass/sepcomp-lib-lto.rs @@ -14,7 +14,6 @@ // aux-build:sepcomp_lib.rs // compile-flags: -C lto -g // no-prefer-dynamic -// ignore-android FIXME #18800 extern crate sepcomp_lib; use sepcomp_lib::a::one; diff --git a/src/test/rustdoc-js/multi-query.js b/src/test/rustdoc-js/multi-query.js index 3793ca6599c..3f583a3600a 100644 --- a/src/test/rustdoc-js/multi-query.js +++ b/src/test/rustdoc-js/multi-query.js @@ -15,6 +15,5 @@ const EXPECTED = { { 'path': 'std', 'name': 'str' }, { 'path': 'std', 'name': 'u8' }, { 'path': 'std::ffi', 'name': 'CStr' }, - { 'path': 'std::simd', 'name': 'u8x2' }, ], }; diff --git a/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.rs b/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.rs new file mode 100644 index 00000000000..e1401653ba3 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:attribute-spans-preserved.rs + +#![feature(use_extern_macros)] + +extern crate attribute_spans_preserved as foo; + +use foo::foo; + +#[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types +#[ bar let x: u32 = "y"; ] //~ ERROR: mismatched types +fn main() { +} diff --git a/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stderr b/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stderr new file mode 100644 index 00000000000..fe62bd23b87 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/attribute-spans-preserved.rs:19:23 + | +LL | #[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types + | ^^^ expected u32, found reference + | + = note: expected type `u32` + found type `&'static str` + +error[E0308]: mismatched types + --> $DIR/attribute-spans-preserved.rs:20:21 + | +LL | #[ bar let x: u32 = "y"; ] //~ ERROR: mismatched types + | ^^^ expected u32, found reference + | + = note: expected type `u32` + found type `&'static str` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stdout b/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stdout new file mode 100644 index 00000000000..33dc064ef68 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stdout @@ -0,0 +1 @@ +fn main ( ) { let y : u32 = "z" ; let x : u32 = "y" ; } diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/attribute-spans-preserved.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/attribute-spans-preserved.rs new file mode 100644 index 00000000000..e725cc7afb8 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/attribute-spans-preserved.rs @@ -0,0 +1,44 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_attribute] +pub fn foo(attr: TokenStream, f: TokenStream) -> TokenStream { + let mut tokens = f.into_iter(); + assert_eq!(tokens.next().unwrap().to_string(), "#"); + let next_attr = match tokens.next().unwrap() { + TokenTree::Group(g) => g, + _ => panic!(), + }; + + let fn_tok = tokens.next().unwrap(); + let ident_tok = tokens.next().unwrap(); + let args_tok = tokens.next().unwrap(); + let body = tokens.next().unwrap(); + + let new_body = attr.into_iter() + .chain(next_attr.stream().into_iter().skip(1)); + + let tokens = vec![ + fn_tok, + ident_tok, + args_tok, + Group::new(Delimiter::Brace, new_body.collect()).into(), + ].into_iter().collect::<TokenStream>(); + println!("{}", tokens); + return tokens +} diff --git a/src/test/ui/imports/glob-shadowing.rs b/src/test/ui/imports/glob-shadowing.rs new file mode 100644 index 00000000000..e4f55137e66 --- /dev/null +++ b/src/test/ui/imports/glob-shadowing.rs @@ -0,0 +1,44 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(decl_macro)] + +mod m { + pub macro env($e: expr) { $e } + pub macro fenv() { 0 } +} + +mod glob_in_normal_module { + use m::*; + fn check() { + let x = env!("PATH"); //~ ERROR `env` is ambiguous + } +} + +mod glob_in_block_module { + fn block() { + use m::*; + fn check() { + let x = env!("PATH"); //~ ERROR `env` is ambiguous + } + } +} + +mod glob_shadows_item { + pub macro fenv($e: expr) { $e } + fn block() { + use m::*; + fn check() { + let x = fenv!(); //~ ERROR `fenv` is ambiguous + } + } +} + +fn main() {} diff --git a/src/test/ui/imports/glob-shadowing.stderr b/src/test/ui/imports/glob-shadowing.stderr new file mode 100644 index 00000000000..7f61cd6c76d --- /dev/null +++ b/src/test/ui/imports/glob-shadowing.stderr @@ -0,0 +1,49 @@ +error[E0659]: `env` is ambiguous + --> $DIR/glob-shadowing.rs:21:17 + | +LL | let x = env!("PATH"); //~ ERROR `env` is ambiguous + | ^^^ + | +note: `env` could refer to the name imported here + --> $DIR/glob-shadowing.rs:19:9 + | +LL | use m::*; + | ^^^^ + = note: `env` is also a builtin macro + = note: consider adding an explicit import of `env` to disambiguate + +error[E0659]: `env` is ambiguous + --> $DIR/glob-shadowing.rs:29:21 + | +LL | let x = env!("PATH"); //~ ERROR `env` is ambiguous + | ^^^ + | +note: `env` could refer to the name imported here + --> $DIR/glob-shadowing.rs:27:13 + | +LL | use m::*; + | ^^^^ + = note: `env` is also a builtin macro + = note: consider adding an explicit import of `env` to disambiguate + +error[E0659]: `fenv` is ambiguous + --> $DIR/glob-shadowing.rs:39:21 + | +LL | let x = fenv!(); //~ ERROR `fenv` is ambiguous + | ^^^^ + | +note: `fenv` could refer to the name imported here + --> $DIR/glob-shadowing.rs:37:13 + | +LL | use m::*; + | ^^^^ +note: `fenv` could also refer to the name defined here + --> $DIR/glob-shadowing.rs:35:5 + | +LL | pub macro fenv($e: expr) { $e } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: consider adding an explicit import of `fenv` to disambiguate + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/tools/clippy b/src/tools/clippy -Subproject c05adc545cff45449d40b1c72070ada7db5fc95 +Subproject 8085ed733fefeaf37aca0a39da93344326de5d5 |
