diff options
| author | bors <bors@rust-lang.org> | 2018-04-05 19:25:37 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-04-05 19:25:37 +0000 |
| commit | 48fa6f9631868b07309b02f479e2ec523bb58c2b (patch) | |
| tree | f42e4285226c191c4448946f440ba79642ba1080 /src | |
| parent | 7222241e7c2d7caf9ad6ee6e34748e4addfb8dd3 (diff) | |
| parent | cd615e9863fa4593ff87243920875ad5bb73906a (diff) | |
| download | rust-48fa6f9631868b07309b02f479e2ec523bb58c2b.tar.gz rust-48fa6f9631868b07309b02f479e2ec523bb58c2b.zip | |
Auto merge of #49696 - alexcrichton:rollup, r=alexcrichton
Rollup of 8 pull requests
Successful merges:
- #49045 (Make queries thread safe)
- #49350 (Expand macros in `extern {}` blocks)
- #49497 (Chalkify - Tweak `Clause` definition and HRTBs)
- #49597 (proc_macro: Reorganize public API)
- #49686 (typos)
- #49621
- #49697
- #49705
Failed merges:
Diffstat (limited to 'src')
53 files changed, 1400 insertions, 435 deletions
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index ea2387b67db..c470ae7eb30 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -130,6 +130,7 @@ exec docker \ --env TRAVIS \ --env TRAVIS_BRANCH \ --env TOOLSTATE_REPO_ACCESS_TOKEN \ + --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \ --volume "$HOME/.cargo:/cargo" \ --volume "$HOME/rustsrc:$HOME/rustsrc" \ --init \ diff --git a/src/ci/run.sh b/src/ci/run.sh index 44eae0d1800..119b239d6b2 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -11,6 +11,10 @@ set -e +if [ -n "$CI_JOB_NAME" ]; then + echo "[CI_JOB_NAME=$CI_JOB_NAME]" +fi + if [ "$NO_CHANGE_USER" = "" ]; then if [ "$LOCAL_USER_ID" != "" ]; then useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 4f9dc61ce19..71b53cc88e5 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -845,3 +845,6 @@ impl<T: ?Sized> fmt::Pointer for PinBox<T> { #[unstable(feature = "pin", issue = "49150")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinBox<U>> for PinBox<T> {} + +#[unstable(feature = "pin", issue = "49150")] +unsafe impl<T: ?Sized> Unpin for PinBox<T> {} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index b2467c948b4..e3f08926610 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1213,3 +1213,6 @@ impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> { #[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Pin<'a, U>> for Pin<'a, T> {} + +#[unstable(feature = "pin", issue = "49150")] +unsafe impl<'a, T: ?Sized> Unpin for Pin<'a, T> {} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 007093981d3..ebd5c834fd0 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -59,7 +59,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::parse::{self, token}; use syntax::symbol::Symbol; use syntax::tokenstream; -use syntax_pos::DUMMY_SP; +use syntax::parse::lexer::comments; use syntax_pos::{FileMap, Pos, SyntaxContext, FileName}; use syntax_pos::hygiene::Mark; @@ -73,7 +73,7 @@ use syntax_pos::hygiene::Mark; /// The API of this type is intentionally bare-bones, but it'll be expanded over /// time! #[stable(feature = "proc_macro_lib", since = "1.15.0")] -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct TokenStream(tokenstream::TokenStream); /// Error returned from `TokenStream::from_str`. @@ -83,6 +83,20 @@ pub struct LexError { _inner: (), } +impl TokenStream { + /// Returns an empty `TokenStream`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn empty() -> TokenStream { + TokenStream(tokenstream::TokenStream::empty()) + } + + /// Checks if this `TokenStream` is empty. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl FromStr for TokenStream { type Err = LexError; @@ -110,19 +124,12 @@ impl fmt::Display for TokenStream { } } -/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input. -/// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs -/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`. -/// -/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. -/// To quote `$` itself, use `$$`. -#[unstable(feature = "proc_macro", issue = "38356")] -#[macro_export] -macro_rules! quote { () => {} } - -#[unstable(feature = "proc_macro_internals", issue = "27812")] -#[doc(hidden)] -mod quote; +#[stable(feature = "proc_macro_lib", since = "1.15.0")] +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} #[unstable(feature = "proc_macro", issue = "38356")] impl From<TokenTree> for TokenStream { @@ -132,62 +139,79 @@ impl From<TokenTree> for TokenStream { } #[unstable(feature = "proc_macro", issue = "38356")] -impl From<TokenNode> for TokenStream { - fn from(kind: TokenNode) -> TokenStream { - TokenTree::from(kind).into() - } -} - -#[unstable(feature = "proc_macro", issue = "38356")] -impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream { - fn from_iter<I: IntoIterator<Item = T>>(streams: I) -> Self { +impl iter::FromIterator<TokenTree> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self { let mut builder = tokenstream::TokenStreamBuilder::new(); - for stream in streams { - builder.push(stream.into().0); + for tree in trees { + builder.push(tree.to_internal()); } TokenStream(builder.build()) } } +/// Implementation details for the `TokenTree` type, such as iterators. #[unstable(feature = "proc_macro", issue = "38356")] -impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = TokenTreeIter; +pub mod token_stream { + use syntax::tokenstream; + use syntax_pos::DUMMY_SP; + + use {TokenTree, TokenStream, Delimiter}; - fn into_iter(self) -> TokenTreeIter { - TokenTreeIter { cursor: self.0.trees(), stack: Vec::new() } + /// An iterator over `TokenTree`s. + #[derive(Clone)] + #[unstable(feature = "proc_macro", issue = "38356")] + pub struct IntoIter { + cursor: tokenstream::Cursor, + stack: Vec<TokenTree>, } -} -impl TokenStream { - /// Returns an empty `TokenStream`. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn empty() -> TokenStream { - TokenStream(tokenstream::TokenStream::empty()) + impl Iterator for IntoIter { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + loop { + let tree = self.stack.pop().or_else(|| { + let next = self.cursor.next_as_stream()?; + Some(TokenTree::from_internal(next, &mut self.stack)) + })?; + if tree.span().0 == DUMMY_SP { + if let TokenTree::Group(ref group) = tree { + if group.delimiter() == Delimiter::None { + self.cursor.insert(group.stream.clone().0); + continue + } + } + } + return Some(tree); + } + } } - /// Checks if this `TokenStream` is empty. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn is_empty(&self) -> bool { - self.0.is_empty() + impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { cursor: self.0.trees(), stack: Vec::new() } + } } } -/// A region of source code, along with macro expansion information. +/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input. +/// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs +/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`. +/// +/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. +/// To quote `$` itself, use `$$`. #[unstable(feature = "proc_macro", issue = "38356")] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct Span(syntax_pos::Span); +#[macro_export] +macro_rules! quote { () => {} } -impl Span { - /// A span that resolves at the macro definition site. - #[unstable(feature = "proc_macro", issue = "38356")] - pub fn def_site() -> Span { - ::__internal::with_sess(|(_, mark)| { - let call_site = mark.expn_info().unwrap().call_site; - Span(call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark))) - }) - } -} +#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[doc(hidden)] +mod quote; /// Quote a `Span` into a `TokenStream`. /// This is needed to implement a custom quoter. @@ -196,6 +220,11 @@ pub fn quote_span(span: Span) -> TokenStream { quote::Quote::quote(span) } +/// A region of source code, along with macro expansion information. +#[unstable(feature = "proc_macro", issue = "38356")] +#[derive(Copy, Clone, Debug)] +pub struct Span(syntax_pos::Span); + macro_rules! diagnostic_method { ($name:ident, $level:expr) => ( /// Create a new `Diagnostic` with the given `message` at the span @@ -208,6 +237,15 @@ macro_rules! diagnostic_method { } impl Span { + /// A span that resolves at the macro definition site. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn def_site() -> Span { + ::__internal::with_sess(|(_, mark)| { + let call_site = mark.expn_info().unwrap().call_site; + Span(call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark))) + }) + } + /// The span of the invocation of the current procedural macro. #[unstable(feature = "proc_macro", issue = "38356")] pub fn call_site() -> Span { @@ -284,6 +322,12 @@ impl Span { other.resolved_at(*self) } + /// Compares to spans to see if they're equal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn eq(&self, other: &Span) -> bool { + self.0 == other.0 + } + diagnostic_method!(error, Level::Error); diagnostic_method!(warning, Level::Warning); diagnostic_method!(note, Level::Note); @@ -379,39 +423,97 @@ impl PartialEq<FileName> for SourceFile { /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). #[unstable(feature = "proc_macro", issue = "38356")] #[derive(Clone, Debug)] -pub struct TokenTree { - /// The `TokenTree`'s span - pub span: Span, - /// Description of the `TokenTree` - pub kind: TokenNode, +pub enum TokenTree { + /// A delimited tokenstream + Group(Group), + /// A unicode identifier + Term(Term), + /// A punctuation character (`+`, `,`, `$`, etc.). + Op(Op), + /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. + Literal(Literal), +} + +impl TokenTree { + /// Returns the span of this token, accessing the `span` method of each of + /// the internal tokens. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn span(&self) -> Span { + match *self { + TokenTree::Group(ref t) => t.span(), + TokenTree::Term(ref t) => t.span(), + TokenTree::Op(ref t) => t.span(), + TokenTree::Literal(ref t) => t.span(), + } + } + + /// Configures the span for *only this token*. + /// + /// Note that if this token is a `Group` then this method will not configure + /// the span of each of the internal tokens, this will simply delegate to + /// the `set_span` method of each variant. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn set_span(&mut self, span: Span) { + match *self { + TokenTree::Group(ref mut t) => t.set_span(span), + TokenTree::Term(ref mut t) => t.set_span(span), + TokenTree::Op(ref mut t) => t.set_span(span), + TokenTree::Literal(ref mut t) => t.set_span(span), + } + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl From<Group> for TokenTree { + fn from(g: Group) -> TokenTree { + TokenTree::Group(g) + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl From<Term> for TokenTree { + fn from(g: Term) -> TokenTree { + TokenTree::Term(g) + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl From<Op> for TokenTree { + fn from(g: Op) -> TokenTree { + TokenTree::Op(g) + } } #[unstable(feature = "proc_macro", issue = "38356")] -impl From<TokenNode> for TokenTree { - fn from(kind: TokenNode) -> TokenTree { - TokenTree { span: Span::def_site(), kind: kind } +impl From<Literal> for TokenTree { + fn from(g: Literal) -> TokenTree { + TokenTree::Literal(g) } } #[unstable(feature = "proc_macro", issue = "38356")] impl fmt::Display for TokenTree { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - TokenStream::from(self.clone()).fmt(f) + match *self { + TokenTree::Group(ref t) => t.fmt(f), + TokenTree::Term(ref t) => t.fmt(f), + TokenTree::Op(ref t) => t.fmt(f), + TokenTree::Literal(ref t) => t.fmt(f), + } } } -/// Description of a `TokenTree` +/// A delimited token stream +/// +/// A `Group` internally contains a `TokenStream` which is delimited by a +/// `Delimiter`. Groups represent multiple tokens internally and have a `Span` +/// for the entire stream. #[derive(Clone, Debug)] #[unstable(feature = "proc_macro", issue = "38356")] -pub enum TokenNode { - /// A delimited tokenstream. - Group(Delimiter, TokenStream), - /// A unicode identifier. - Term(Term), - /// A punctuation character (`+`, `,`, `$`, etc.). - Op(char, Spacing), - /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`). - Literal(Literal), +pub struct Group { + delimiter: Delimiter, + stream: TokenStream, + span: Span, } /// Describes how a sequence of token trees is delimited. @@ -428,25 +530,74 @@ pub enum Delimiter { None, } -/// An interned string. -#[derive(Copy, Clone, Debug)] -#[unstable(feature = "proc_macro", issue = "38356")] -pub struct Term(Symbol); +impl Group { + /// Creates a new `group` with the given delimiter and token stream. + /// + /// This constructor will set the span for this group to + /// `Span::call_site()`. To change the span you can use the `set_span` + /// method below. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { + Group { + delimiter: delimiter, + stream: stream, + span: Span::call_site(), + } + } -impl Term { - /// Intern a string into a `Term`. + /// Returns the delimiter of this `Group` #[unstable(feature = "proc_macro", issue = "38356")] - pub fn intern(string: &str) -> Term { - Term(Symbol::intern(string)) + pub fn delimiter(&self) -> Delimiter { + self.delimiter } - /// Get a reference to the interned string. + /// Returns the `TokenStream` of tokens that are delimited in this `Group`. + /// + /// Note that the returned token stream does not include the delimiter + /// returned above. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn as_str(&self) -> &str { - unsafe { &*(&*self.0.as_str() as *const str) } + pub fn stream(&self) -> TokenStream { + self.stream.clone() + } + + /// Returns the span for the delimiters of this token stream, spanning the + /// entire `Group`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn span(&self) -> Span { + self.span + } + + /// Configures the span for this `Group`'s delimiters, but not its internal + /// tokens. + /// + /// This method will **not** set the span of all the internal tokens spanned + /// by this group, but rather it will only set the span of the delimiter + /// tokens at the level of the `Group`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn set_span(&mut self, span: Span) { + self.span = span; } } +#[unstable(feature = "proc_macro", issue = "38356")] +impl fmt::Display for Group { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + TokenStream::from(TokenTree::from(self.clone())).fmt(f) + } +} + +/// An `Op` is an operator like `+` or `-`, and only represents one character. +/// +/// Operators like `+=` are represented as two instance of `Op` with different +/// forms of `Spacing` returned. +#[unstable(feature = "proc_macro", issue = "38356")] +#[derive(Copy, Clone, Debug)] +pub struct Op { + op: char, + spacing: Spacing, + span: Span, +} + /// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "proc_macro", issue = "38356")] @@ -457,68 +608,285 @@ pub enum Spacing { Joint, } -/// A literal character (`'a'`), string (`"hello"`), or number (`2.3`). -#[derive(Clone, Debug)] +impl Op { + /// Creates a new `Op` from the given character and spacing. + /// + /// The returned `Op` will have the default span of `Span::call_site()` + /// which can be further configured with the `set_span` method below. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn new(op: char, spacing: Spacing) -> Op { + Op { + op: op, + spacing: spacing, + span: Span::call_site(), + } + } + + /// Returns the character this operation represents, for example `'+'` + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn op(&self) -> char { + self.op + } + + /// Returns the spacing of this operator, indicating whether it's a joint + /// operator with more operators coming next in the token stream or an + /// `Alone` meaning that the operator has ended. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn spacing(&self) -> Spacing { + self.spacing + } + + /// Returns the span for this operator character + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn span(&self) -> Span { + self.span + } + + /// Configure the span for this operator's character + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + #[unstable(feature = "proc_macro", issue = "38356")] -pub struct Literal(token::Token); +impl fmt::Display for Op { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + TokenStream::from(TokenTree::from(self.clone())).fmt(f) + } +} +/// An interned string. +#[derive(Copy, Clone, Debug)] #[unstable(feature = "proc_macro", issue = "38356")] -impl fmt::Display for Literal { +pub struct Term { + sym: Symbol, + span: Span, +} + +impl Term { + /// Creates a new `Term` with the given `string` as well as the specified + /// `span`. + /// + /// Note that `span`, currently in rustc, configures the hygiene information + /// for this identifier. As of this time `Span::call_site()` explicitly + /// opts-in to **non-hygienic** information (aka copy/pasted code) while + /// spans like `Span::def_site()` will opt-in to hygienic information, + /// meaning that code at the call site of the macro can't access this + /// identifier. + /// + /// Due to the current importance of hygiene this constructor, unlike other + /// tokens, requires a `Span` to be specified at construction. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn new(string: &str, span: Span) -> Term { + Term { + sym: Symbol::intern(string), + span, + } + } + + /// Get a reference to the interned string. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn as_str(&self) -> &str { + unsafe { &*(&*self.sym.as_str() as *const str) } + } + + /// Returns the span of this `Term`, encompassing the entire string returned + /// by `as_str`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn span(&self) -> Span { + self.span + } + + /// Configures the span of this `Term`, possibly changing hygiene + /// information. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl fmt::Display for Term { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - TokenTree { kind: TokenNode::Literal(self.clone()), span: Span(DUMMY_SP) }.fmt(f) + self.as_str().fmt(f) } } -macro_rules! int_literals { - ($($int_kind:ident),*) => {$( - /// Integer literal. +/// A literal character (`'a'`), string (`"hello"`), a number (`2.3`), etc. +#[derive(Clone, Debug)] +#[unstable(feature = "proc_macro", issue = "38356")] +pub struct Literal { + token: token::Token, + span: Span, +} + +macro_rules! suffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new suffixed integer literal with the specified value. + /// + /// This function will create an integer like `1u32` where the integer + /// value specified is the first part of the token and the integral is + /// also suffixed at the end. + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn $int_kind(n: $int_kind) -> Literal { - Literal::typed_integer(n as i128, stringify!($int_kind)) + pub fn $name(n: $kind) -> Literal { + let lit = token::Lit::Integer(Symbol::intern(&n.to_string())); + let ty = Some(Symbol::intern(stringify!($kind))); + Literal { + token: token::Literal(lit, ty), + span: Span::call_site(), + } } - )*} + )*) +} + +macro_rules! unsuffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new unsuffixed integer literal with the specified value. + /// + /// This function will create an integer like `1` where the integer + /// value specified is the first part of the token. No suffix is + /// specified on this token, meaning that invocations like + /// `Literal::i8_unsuffixed(1)` are equivalent to + /// `Literal::u32_unsuffixed(1)`. + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn $name(n: $kind) -> Literal { + let lit = token::Lit::Integer(Symbol::intern(&n.to_string())); + Literal { + token: token::Literal(lit, None), + span: Span::call_site(), + } + } + )*) } impl Literal { - /// Integer literal - #[unstable(feature = "proc_macro", issue = "38356")] - pub fn integer(n: i128) -> Literal { - Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), None)) + suffixed_int_literals! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, } - int_literals!(u8, i8, u16, i16, u32, i32, u64, i64, usize, isize); - fn typed_integer(n: i128, kind: &'static str) -> Literal { - Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), - Some(Symbol::intern(kind)))) + unsuffixed_int_literals! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, } - /// Floating point literal. + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed` where + /// the float's value is emitted directly into the token but no suffix is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for + /// example if it is infinity or NaN this function will panic. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn float(n: f64) -> Literal { + pub fn f32_unsuffixed(n: f32) -> Literal { if !n.is_finite() { panic!("Invalid float literal {}", n); } - Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), None)) + let lit = token::Lit::Float(Symbol::intern(&n.to_string())); + Literal { + token: token::Literal(lit, None), + span: Span::call_site(), + } } - /// Floating point literal. + /// Creates a new suffixed floating-point literal. + /// + /// This consturctor will create a literal like `1.0f32` where the value + /// specified is the preceding part of the token and `f32` is the suffix of + /// the token. This token will always be inferred to be an `f32` in the + /// compiler. + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for + /// example if it is infinity or NaN this function will panic. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn f32(n: f32) -> Literal { + pub fn f32_suffixed(n: f32) -> Literal { if !n.is_finite() { - panic!("Invalid f32 literal {}", n); + panic!("Invalid float literal {}", n); + } + let lit = token::Lit::Float(Symbol::intern(&n.to_string())); + Literal { + token: token::Literal(lit, Some(Symbol::intern("f32"))), + span: Span::call_site(), } - Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), - Some(Symbol::intern("f32")))) } - /// Floating point literal. + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed` where + /// the float's value is emitted directly into the token but no suffix is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for + /// example if it is infinity or NaN this function will panic. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn f64(n: f64) -> Literal { + pub fn f64_unsuffixed(n: f64) -> Literal { if !n.is_finite() { - panic!("Invalid f64 literal {}", n); + panic!("Invalid float literal {}", n); + } + let lit = token::Lit::Float(Symbol::intern(&n.to_string())); + Literal { + token: token::Literal(lit, None), + span: Span::call_site(), + } + } + + /// Creates a new suffixed floating-point literal. + /// + /// This consturctor will create a literal like `1.0f64` where the value + /// specified is the preceding part of the token and `f64` is the suffix of + /// the token. This token will always be inferred to be an `f64` in the + /// compiler. + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for + /// example if it is infinity or NaN this function will panic. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn f64_suffixed(n: f64) -> Literal { + if !n.is_finite() { + panic!("Invalid float literal {}", n); + } + let lit = token::Lit::Float(Symbol::intern(&n.to_string())); + Literal { + token: token::Literal(lit, Some(Symbol::intern("f64"))), + span: Span::call_site(), } - Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), - Some(Symbol::intern("f64")))) } /// String literal. @@ -528,7 +896,10 @@ impl Literal { for ch in string.chars() { escaped.extend(ch.escape_debug()); } - Literal(token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None)) + Literal { + token: token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None), + span: Span::call_site(), + } } /// Character literal. @@ -536,7 +907,10 @@ impl Literal { pub fn character(ch: char) -> Literal { let mut escaped = String::new(); escaped.extend(ch.escape_unicode()); - Literal(token::Literal(token::Lit::Char(Symbol::intern(&escaped)), None)) + Literal { + token: token::Literal(token::Lit::Char(Symbol::intern(&escaped)), None), + span: Span::call_site(), + } } /// Byte string literal. @@ -544,36 +918,29 @@ impl Literal { pub fn byte_string(bytes: &[u8]) -> Literal { let string = bytes.iter().cloned().flat_map(ascii::escape_default) .map(Into::<char>::into).collect::<String>(); - Literal(token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None)) + Literal { + token: token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None), + span: Span::call_site(), + } } -} -/// An iterator over `TokenTree`s. -#[derive(Clone)] -#[unstable(feature = "proc_macro", issue = "38356")] -pub struct TokenTreeIter { - cursor: tokenstream::Cursor, - stack: Vec<TokenTree>, + /// Returns the span encompassing this literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn span(&self) -> Span { + self.span + } + + /// Configures the span associated for this literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn set_span(&mut self, span: Span) { + self.span = span; + } } #[unstable(feature = "proc_macro", issue = "38356")] -impl Iterator for TokenTreeIter { - type Item = TokenTree; - - fn next(&mut self) -> Option<TokenTree> { - loop { - let tree = self.stack.pop().or_else(|| { - let next = self.cursor.next_as_stream()?; - Some(TokenTree::from_internal(next, &mut self.stack)) - })?; - if tree.span.0 == DUMMY_SP { - if let TokenNode::Group(Delimiter::None, stream) = tree.kind { - self.cursor.insert(stream.0); - continue - } - } - return Some(tree); - } +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + TokenStream::from(TokenTree::from(self.clone())).fmt(f) } } @@ -607,31 +974,34 @@ impl TokenTree { tokenstream::TokenTree::Token(span, token) => (span, token), tokenstream::TokenTree::Delimited(span, delimed) => { let delimiter = Delimiter::from_internal(delimed.delim); - return TokenTree { - span: Span(span), - kind: TokenNode::Group(delimiter, TokenStream(delimed.tts.into())), - }; + 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) => (TokenTree { span: Span(span), kind: $e }) + ($e:expr) => ({ + let mut x = TokenTree::from($e); + x.set_span(Span(span)); + x + }) } macro_rules! op { - ($a:expr) => (TokenNode::Op($a, op_kind)); + ($a:expr) => (tt!(Op::new($a, op_kind))); ($a:expr, $b:expr) => ({ - stack.push(tt!(TokenNode::Op($b, op_kind).into())); - TokenNode::Op($a, Spacing::Joint) + stack.push(tt!(Op::new($b, op_kind))); + tt!(Op::new($a, Spacing::Joint)) }); ($a:expr, $b:expr, $c:expr) => ({ - stack.push(tt!(TokenNode::Op($c, op_kind))); - stack.push(tt!(TokenNode::Op($b, Spacing::Joint))); - TokenNode::Op($a, Spacing::Joint) + stack.push(tt!(Op::new($c, op_kind))); + stack.push(tt!(Op::new($b, Spacing::Joint))); + tt!(Op::new($a, Spacing::Joint)) }) } - let kind = match token { + match token { Eq => op!('='), Lt => op!('<'), Le => op!('<', '='), @@ -679,80 +1049,93 @@ impl TokenTree { Dollar => op!('$'), Question => op!('?'), - Ident(ident, false) | Lifetime(ident) => TokenNode::Term(Term(ident.name)), - Ident(ident, true) => TokenNode::Term(Term(Symbol::intern(&format!("r#{}", ident)))), - Literal(..) => TokenNode::Literal(self::Literal(token)), + Ident(ident, false) | Lifetime(ident) => { + tt!(Term::new(&ident.name.as_str(), Span(span))) + } + Ident(ident, true) => { + tt!(Term::new(&format!("r#{}", ident), Span(span))) + } + Literal(..) => tt!(self::Literal { token, 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!(TokenNode::Term(Term::intern("doc"))), - tt!(op!('=')), - tt!(TokenNode::Literal(self::Literal(Literal(Lit::Str_(c), None)))), + tt!(Term::new("doc", Span(span))), + tt!(Op::new('=', Spacing::Alone)), + tt!(self::Literal::string(&stripped)), ].into_iter().collect(); - stack.push(tt!(TokenNode::Group(Delimiter::Bracket, stream))); - op!('#') + stack.push(tt!(Group::new(Delimiter::Bracket, stream))); + if style == ast::AttrStyle::Inner { + stack.push(tt!(Op::new('!', Spacing::Alone))); + } + tt!(Op::new('#', Spacing::Alone)) } Interpolated(_) => { __internal::with_sess(|(sess, _)| { let tts = token.interpolated_to_tokenstream(sess, span); - TokenNode::Group(Delimiter::None, TokenStream(tts)) + tt!(Group::new(Delimiter::None, TokenStream(tts))) }) } DotEq => op!('.', '='), OpenDelim(..) | CloseDelim(..) => unreachable!(), Whitespace | Comment | Shebang(..) | Eof => unreachable!(), - }; - - TokenTree { span: Span(span), kind: kind } + } } fn to_internal(self) -> tokenstream::TokenStream { use syntax::parse::token::*; use syntax::tokenstream::{TokenTree, Delimited}; - let (op, kind) = match self.kind { - TokenNode::Op(op, kind) => (op, kind), - TokenNode::Group(delimiter, tokens) => { - return TokenTree::Delimited(self.span.0, Delimited { - delim: delimiter.to_internal(), - tts: tokens.0.into(), + let (op, kind, span) = match self { + self::TokenTree::Op(tt) => (tt.op(), 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(); }, - TokenNode::Term(symbol) => { - let ident = ast::Ident { name: symbol.0, ctxt: self.span.0.ctxt() }; - let sym_str = symbol.0.as_str(); + self::TokenTree::Term(tt) => { + let ident = ast::Ident { name: tt.sym, ctxt: tt.span.0.ctxt() }; + let sym_str = tt.sym.as_str(); let token = if sym_str.starts_with("'") { Lifetime(ident) } else if sym_str.starts_with("r#") { let name = Symbol::intern(&sym_str[2..]); - let ident = ast::Ident { name, ctxt: self.span.0.ctxt() }; + let ident = ast::Ident { name, ctxt: tt.span.0.ctxt() }; Ident(ident, true) } else { Ident(ident, false) }; - return TokenTree::Token(self.span.0, token).into(); + return TokenTree::Token(tt.span.0, token).into(); } - TokenNode::Literal(self::Literal(Literal(Lit::Integer(ref a), b))) + self::TokenTree::Literal(self::Literal { + token: Literal(Lit::Integer(ref a), b), + 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), b); - let a = TokenTree::Token(self.span.0, minus); - let b = TokenTree::Token(self.span.0, integer); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, integer); return vec![a, b].into_iter().collect() } - TokenNode::Literal(self::Literal(Literal(Lit::Float(ref a), b))) + self::TokenTree::Literal(self::Literal { + token: Literal(Lit::Float(ref a), b), + 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), b); - let a = TokenTree::Token(self.span.0, minus); - let b = TokenTree::Token(self.span.0, float); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, float); return vec![a, b].into_iter().collect() } - TokenNode::Literal(token) => { - return TokenTree::Token(self.span.0, token.0).into() + self::TokenTree::Literal(tt) => { + return TokenTree::Token(tt.span.0, tt.token).into() } }; @@ -781,7 +1164,7 @@ impl TokenTree { _ => panic!("unsupported character {}", op), }; - let tree = TokenTree::Token(self.span.0, token); + let tree = TokenTree::Token(span.0, token); match kind { Spacing::Alone => tree.into(), Spacing::Joint => tree.joint(), diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index 8b5add1a0f0..cc8575b88be 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -14,7 +14,7 @@ //! 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, Term, TokenNode, TokenStream, TokenTree}; +use {Delimiter, Literal, Spacing, Span, Term, Op, Group, TokenStream, TokenTree}; use syntax::ext::base::{ExtCtxt, ProcMacro}; use syntax::parse::token; @@ -23,47 +23,59 @@ use syntax::tokenstream; pub struct Quoter; pub fn unquote<T: Into<TokenStream> + Clone>(tokens: &T) -> TokenStream { - T::into(tokens.clone()) + tokens.clone().into() } pub trait Quote { fn quote(self) -> TokenStream; } +macro_rules! tt2ts { + ($e:expr) => (TokenStream::from(TokenTree::from($e))) +} + macro_rules! quote_tok { - (,) => { TokenNode::Op(',', Spacing::Alone) }; - (.) => { TokenNode::Op('.', Spacing::Alone) }; - (:) => { TokenNode::Op(':', Spacing::Alone) }; + (,) => { tt2ts!(Op::new(',', Spacing::Alone)) }; + (.) => { tt2ts!(Op::new('.', Spacing::Alone)) }; + (:) => { tt2ts!(Op::new(':', Spacing::Alone)) }; + (|) => { tt2ts!(Op::new('|', Spacing::Alone)) }; (::) => { [ - TokenNode::Op(':', Spacing::Joint), - TokenNode::Op(':', Spacing::Alone) - ].iter().cloned().collect::<TokenStream>() + TokenTree::from(Op::new(':', Spacing::Joint)), + TokenTree::from(Op::new(':', Spacing::Alone)), + ].iter() + .cloned() + .map(|mut x| { + x.set_span(Span::def_site()); + x + }) + .collect::<TokenStream>() }; - (!) => { TokenNode::Op('!', Spacing::Alone) }; - (<) => { TokenNode::Op('<', Spacing::Alone) }; - (>) => { TokenNode::Op('>', Spacing::Alone) }; - (_) => { TokenNode::Op('_', Spacing::Alone) }; - (0) => { TokenNode::Literal(::Literal::integer(0)) }; - (&) => { TokenNode::Op('&', Spacing::Alone) }; - ($i:ident) => { TokenNode::Term(Term::intern(stringify!($i))) }; + (!) => { tt2ts!(Op::new('!', Spacing::Alone)) }; + (<) => { tt2ts!(Op::new('<', Spacing::Alone)) }; + (>) => { tt2ts!(Op::new('>', Spacing::Alone)) }; + (_) => { tt2ts!(Op::new('_', Spacing::Alone)) }; + (0) => { tt2ts!(Literal::i8_unsuffixed(0)) }; + (&) => { tt2ts!(Op::new('&', Spacing::Alone)) }; + ($i:ident) => { tt2ts!(Term::new(stringify!($i), Span::def_site())) }; } macro_rules! quote_tree { ((unquote $($t:tt)*)) => { $($t)* }; ((quote $($t:tt)*)) => { ($($t)*).quote() }; - (($($t:tt)*)) => { TokenNode::Group(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { TokenNode::Group(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { TokenNode::Group(Delimiter::Brace, quote!($($t)*)) }; + (($($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) }; } macro_rules! quote { () => { TokenStream::empty() }; ($($t:tt)*) => { - [ - $(TokenStream::from(quote_tree!($t)),)* - ].iter().cloned().collect::<TokenStream>() + [$(quote_tree!($t),)*].iter() + .cloned() + .flat_map(|x| x.into_iter()) + .collect::<TokenStream>() }; } @@ -97,72 +109,81 @@ impl Quote for TokenStream { let tokens = self.into_iter().filter_map(|tree| { if after_dollar { after_dollar = false; - match tree.kind { - TokenNode::Term(_) => { + match tree { + TokenTree::Term(_) => { + let tree = TokenStream::from(tree); return Some(quote!(::__internal::unquote(&(unquote tree)),)); } - TokenNode::Op('$', _) => {} + TokenTree::Op(ref tt) if tt.op() == '$' => {} _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), } - } else if let TokenNode::Op('$', _) = tree.kind { - after_dollar = true; - return None; + } else if let TokenTree::Op(tt) = tree { + if tt.op() == '$' { + after_dollar = true; + return None; + } } Some(quote!(::TokenStream::from((quote tree)),)) - }).collect::<TokenStream>(); + }).flat_map(|t| t.into_iter()).collect::<TokenStream>(); if after_dollar { panic!("unexpected trailing `$` in `quote!`"); } - quote!([(unquote tokens)].iter().cloned().collect::<::TokenStream>()) + quote!( + [(unquote tokens)].iter() + .cloned() + .flat_map(|x| x.into_iter()) + .collect::<::TokenStream>() + ) } } impl Quote for TokenTree { fn quote(self) -> TokenStream { - quote!(::TokenTree { span: (quote self.span), kind: (quote self.kind) }) + match self { + TokenTree::Op(tt) => quote!(::TokenTree::Op( (quote tt) )), + TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )), + TokenTree::Term(tt) => quote!(::TokenTree::Term( (quote tt) )), + TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )), + } } } -impl Quote for TokenNode { +impl Quote for char { fn quote(self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident($($arg:ident),+)),*) => { - match self { - $(TokenNode::$i($($arg),+) => quote! { - ::TokenNode::$i($((quote $arg)),+) - },)* - } - } - } + TokenTree::from(Literal::character(self)).into() + } +} - gen_match! { Op(op, kind), Group(delim, tokens), Term(term), Literal(lit) } +impl<'a> Quote for &'a str { + fn quote(self) -> TokenStream { + TokenTree::from(Literal::string(self)).into() } } -impl Quote for char { +impl Quote for usize { fn quote(self) -> TokenStream { - TokenNode::Literal(Literal::character(self)).into() + TokenTree::from(Literal::usize_unsuffixed(self)).into() } } -impl<'a> Quote for &'a str { +impl Quote for Group { fn quote(self) -> TokenStream { - TokenNode::Literal(Literal::string(self)).into() + quote!(::Group::new((quote self.delimiter()), (quote self.stream()))) } } -impl Quote for usize { +impl Quote for Op { fn quote(self) -> TokenStream { - TokenNode::Literal(Literal::integer(self as i128)).into() + quote!(::Op::new((quote self.op()), (quote self.spacing()))) } } impl Quote for Term { fn quote(self) -> TokenStream { - quote!(::Term::intern((quote self.as_str()))) + quote!(::Term::new((quote self.as_str()), (quote self.span()))) } } @@ -182,14 +203,20 @@ macro_rules! literals { impl LiteralKind { pub fn with_contents_and_suffix(self, contents: Term, suffix: Option<Term>) -> Literal { - let contents = contents.0; - let suffix = suffix.map(|t| t.0); + let sym = contents.sym; + let suffix = suffix.map(|t| t.sym); match self { $(LiteralKind::$i => { - Literal(token::Literal(token::Lit::$i(contents), suffix)) + Literal { + token: token::Literal(token::Lit::$i(sym), suffix), + span: contents.span, + } })* $(LiteralKind::$raw(n) => { - Literal(token::Literal(token::Lit::$raw(contents, n), suffix)) + Literal { + token: token::Literal(token::Lit::$raw(sym, n), suffix), + span: contents.span, + } })* } } @@ -197,16 +224,17 @@ macro_rules! literals { impl Literal { fn kind_contents_and_suffix(self) -> (LiteralKind, Term, Option<Term>) { - let (lit, suffix) = match self.0 { + let (lit, suffix) = match self.token { token::Literal(lit, suffix) => (lit, suffix), - _ => panic!("unsupported literal {:?}", self.0), + _ => panic!("unsupported literal {:?}", self.token), }; let (kind, contents) = match lit { $(token::Lit::$i(contents) => (LiteralKind::$i, contents),)* $(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)* }; - (kind, Term(contents), suffix.map(Term)) + let suffix = suffix.map(|sym| Term::new(&sym.as_str(), self.span())); + (kind, Term::new(&contents.as_str(), self.span()), suffix) } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5f9f37094f5..b767ede5faa 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2724,6 +2724,7 @@ impl<'a> LoweringContext<'a> { hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m) } ForeignItemKind::Ty => hir::ForeignItemType, + ForeignItemKind::Macro(_) => panic!("shouldn't exist here"), }, vis: this.lower_visibility(&i.vis, None), span: i.span, diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 3619a7fb0c6..20f46cb348d 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -181,6 +181,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { + if let ForeignItemKind::Macro(_) = foreign_item.node { + return self.visit_macro_invoc(foreign_item.id, false); + } + let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.ident.name.as_str()), REGULAR_SPACE, diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 340dd32a237..da1a2592f14 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1392,6 +1392,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> { } } +impl_stable_hash_for!( + impl<'tcx> for struct traits::ProgramClause<'tcx> { + goal, hypotheses + } +); + impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Clause<'tcx> { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, @@ -1400,11 +1406,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Clause<'tcx> { mem::discriminant(self).hash_stable(hcx, hasher); match self { - Implies(hypotheses, goal) => { - hypotheses.hash_stable(hcx, hasher); - goal.hash_stable(hcx, hasher); - } - DomainGoal(domain_goal) => domain_goal.hash_stable(hcx, hasher), + Implies(clause) => clause.hash_stable(hcx, hasher), ForAll(clause) => clause.hash_stable(hcx, hasher), } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 2ce1b75e315..b30fb2ce016 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -272,6 +272,8 @@ pub enum DomainGoal<'tcx> { TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), } +pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>; + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum QuantifierKind { Universal, @@ -294,9 +296,15 @@ impl<'tcx> From<DomainGoal<'tcx>> for Goal<'tcx> { } } -impl<'tcx> From<DomainGoal<'tcx>> for Clause<'tcx> { - fn from(domain_goal: DomainGoal<'tcx>) -> Self { - Clause::DomainGoal(domain_goal) +impl<'tcx> From<PolyDomainGoal<'tcx>> for Goal<'tcx> { + fn from(domain_goal: PolyDomainGoal<'tcx>) -> Self { + match domain_goal.no_late_bound_regions() { + Some(p) => p.into(), + None => Goal::Quantified( + QuantifierKind::Universal, + Box::new(domain_goal.map_bound(|p| p.into())) + ), + } } } @@ -304,10 +312,23 @@ impl<'tcx> From<DomainGoal<'tcx>> for Clause<'tcx> { /// Harrop Formulas". #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Clause<'tcx> { - // FIXME: again, use interned refs instead of `Box` - Implies(Vec<Goal<'tcx>>, DomainGoal<'tcx>), - DomainGoal(DomainGoal<'tcx>), - ForAll(Box<ty::Binder<Clause<'tcx>>>), + Implies(ProgramClause<'tcx>), + ForAll(ty::Binder<ProgramClause<'tcx>>), +} + +/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying +/// that the domain goal `D` is true if `G1...Gn` are provable. This +/// is equivalent to the implication `G1..Gn => D`; we usually write +/// it with the reverse implication operator `:-` to emphasize the way +/// that programs are actually solved (via backchaining, which starts +/// with the goal to solve and proceeds from there). +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct ProgramClause<'tcx> { + /// This goal will be considered true... + pub goal: DomainGoal<'tcx>, + + /// ...if we can prove these hypotheses (there may be no hypotheses at all): + pub hypotheses: Vec<Goal<'tcx>>, } pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index d6e6f0e98ad..865a9a34aaa 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -493,25 +493,29 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> { } } +impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let traits::ProgramClause { goal, hypotheses } = self; + write!(fmt, "{}", goal)?; + if !hypotheses.is_empty() { + write!(fmt, " :- ")?; + for (index, condition) in hypotheses.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", condition)?; + } + } + write!(fmt, ".") + } +} + impl<'tcx> fmt::Display for traits::Clause<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use traits::Clause::*; match self { - Implies(hypotheses, goal) => { - write!(fmt, "{}", goal)?; - if !hypotheses.is_empty() { - write!(fmt, " :- ")?; - for (index, condition) in hypotheses.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", condition)?; - } - } - write!(fmt, ".") - } - DomainGoal(domain_goal) => write!(fmt, "{}.", domain_goal), + Implies(clause) => write!(fmt, "{}", clause), ForAll(clause) => { // FIXME: appropriate binder names write!(fmt, "forall<> {{ {} }}", clause.skip_binder()) @@ -553,10 +557,16 @@ EnumTypeFoldableImpl! { } } +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::ProgramClause<'tcx> { + goal, + hypotheses + } +} + EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for traits::Clause<'tcx> { - (traits::Clause::Implies)(hypotheses, goal), - (traits::Clause::DomainGoal)(domain_goal), + (traits::Clause::Implies)(clause), (traits::Clause::ForAll)(clause), } } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 37274d1fc44..b34decc1c69 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -381,7 +381,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .span_label(span, "pattern not allowed in foreign function").emit(); }); } - ForeignItemKind::Static(..) | ForeignItemKind::Ty => {} + ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} } visit::walk_foreign_item(self, fi) @@ -460,6 +460,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_late_bound_lifetime_defs(&t.bound_generic_params); visit::walk_poly_trait_ref(self, t, m); } + + fn visit_mac(&mut self, mac: &Spanned<Mac_>) { + // when a new macro kind is added but the author forgets to set it up for expansion + // because that's the only part that won't cause a compiler error + self.session.diagnostic() + .span_bug(mac.span, "macro invocation missed in expansion; did you forget to override \ + the relevant `fold_*()` method in `PlaceholderExpander`?"); + } } // Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`. @@ -522,6 +530,10 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { } } } + + fn visit_mac(&mut self, _mac: &Spanned<Mac_>) { + // covered in AstValidator + } } // Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`. @@ -583,6 +595,10 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> { _ => visit::walk_ty(self, t), } } + + fn visit_mac(&mut self, _mac: &Spanned<Mac_>) { + // covered in AstValidator + } } pub fn check_crate(session: &Session, krate: &Crate) { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c192f349c20..397590012fd 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -456,6 +456,7 @@ impl<'a> Resolver<'a> { ForeignItemKind::Ty => { (Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS) } + ForeignItemKind::Macro(_) => unreachable!(), }; let parent = self.current_module; let vis = self.resolve_visibility(&item.vis); @@ -816,6 +817,11 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { + if let ForeignItemKind::Macro(_) = foreign_item.node { + self.visit_invoc(foreign_item.id); + return; + } + self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion); visit::walk_foreign_item(self, foreign_item); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3a97d276744..64d57ea34c2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -863,6 +863,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { } ForeignItemKind::Static(..) => NoTypeParameters, ForeignItemKind::Ty => NoTypeParameters, + ForeignItemKind::Macro(..) => NoTypeParameters, }; self.with_type_parameter_rib(type_parameters, |this| { visit::walk_foreign_item(this, foreign_item); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3d4d8571c6e..5e51797d720 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1812,6 +1812,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.dumper.dump_def(&access, var_data); } } + ast::ForeignItemKind::Macro(..) => {} } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 95374775651..fb4cb2afe5a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -182,6 +182,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } // FIXME(plietar): needs a new DefKind in rls-data ast::ForeignItemKind::Ty => None, + ast::ForeignItemKind::Macro(..) => None, } } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 0c890ce19d0..fd4d3e76386 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -822,6 +822,7 @@ impl Sig for ast::ForeignItem { refs: vec![], }) } + ast::ForeignItemKind::Macro(..) => Err("macro"), } } } diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 1092e826a35..153b2e73033 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -13,7 +13,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::ty::{self, TyCtxt}; use rustc::ty::subst::Substs; -use rustc::traits::{QuantifierKind, Goal, DomainGoal, Clause, WhereClauseAtom}; +use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause}; use syntax::ast; use rustc_data_structures::sync::Lrc; @@ -61,28 +61,19 @@ impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> { /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic /// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things /// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous -/// example), we model them with quantified goals, e.g. as for the previous example: +/// example), we model them with quantified domain goals, e.g. as for the previous example: /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like /// `Binder<Holds(Implemented(TraitPredicate))>`. -/// -/// Also, if `self` does not contain generic lifetimes, we can safely drop the binder and we -/// can directly lower to a leaf goal instead of a quantified goal. -impl<'tcx, T> Lower<Goal<'tcx>> for ty::Binder<T> - where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx> + Copy +impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T> + where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx> { - fn lower(&self) -> Goal<'tcx> { - match self.no_late_bound_regions() { - Some(p) => p.lower().into(), - None => Goal::Quantified( - QuantifierKind::Universal, - Box::new(self.map_bound(|p| p.lower().into())) - ), - } + fn lower(&self) -> PolyDomainGoal<'tcx> { + self.map_bound_ref(|p| p.lower()) } } -impl<'tcx> Lower<Goal<'tcx>> for ty::Predicate<'tcx> { - fn lower(&self) -> Goal<'tcx> { +impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> { + fn lower(&self) -> PolyDomainGoal<'tcx> { use rustc::ty::Predicate::*; match self { @@ -90,7 +81,7 @@ impl<'tcx> Lower<Goal<'tcx>> for ty::Predicate<'tcx> { RegionOutlives(predicate) => predicate.lower(), TypeOutlives(predicate) => predicate.lower(), Projection(predicate) => predicate.lower(), - WellFormed(ty) => DomainGoal::WellFormedTy(*ty).into(), + WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)), ObjectSafe(..) | ClosureKind(..) | Subtype(..) | @@ -134,13 +125,16 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI } }; // `FromEnv(Self: Trait<P1..Pn>)` - let from_env = Goal::DomainGoal(DomainGoal::FromEnv(trait_pred.lower())); + let from_env = DomainGoal::FromEnv(trait_pred.lower()).into(); // `Implemented(Self: Trait<P1..Pn>)` let impl_trait = DomainGoal::Holds(WhereClauseAtom::Implemented(trait_pred)); // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)` - let clause = Clause::Implies(vec![from_env], impl_trait); - Lrc::new(vec![clause]) + let clause = ProgramClause { + goal: impl_trait, + hypotheses: vec![from_env], + }; + Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))]) } fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -167,8 +161,11 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId let where_clauses = tcx.predicates_of(def_id).predicates.lower(); // `Implemented(A0: Trait<A1..An>) :- WC` - let clause = Clause::Implies(where_clauses, trait_pred); - Lrc::new(vec![clause]) + let clause = ProgramClause { + goal: trait_pred, + hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect() + }; + Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))]) } pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { @@ -184,14 +181,19 @@ struct ClauseDumper<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, } -impl <'a, 'tcx> ClauseDumper<'a, 'tcx > { +impl<'a, 'tcx> ClauseDumper<'a, 'tcx > { fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) { let def_id = self.tcx.hir.local_def_id(node_id); for attr in attrs { if attr.check_name("rustc_dump_program_clauses") { let clauses = self.tcx.program_clauses_for(def_id); for clause in &*clauses { - self.tcx.sess.struct_span_err(attr.span, &format!("{}", clause)).emit(); + // Skip the top-level binder for a less verbose output + let program_clause = match clause { + Clause::Implies(program_clause) => program_clause, + Clause::ForAll(program_clause) => program_clause.skip_binder(), + }; + self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit(); } } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3f1fec4c317..6f6abfdd31e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -378,7 +378,7 @@ extern crate compiler_builtins; // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they -// wolud generate duplicate lang item errors), and any globals it defines are +// would generate duplicate lang item errors), and any globals it defines are // _not_ the globals used by "real" std. So this import, defined only during // testing gives test-std access to real-std lang items and globals. See #2912 #[cfg(test)] extern crate std as realstd; diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 79857104b9b..28c178307a5 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -188,7 +188,7 @@ pub struct AssertUnwindSafe<T>( // * By default everything is unwind safe // * pointers T contains mutability of some form are not unwind safe // * Unique, an owning pointer, lifts an implementation -// * Types like Mutex/RwLock which are explicilty poisoned are unwind safe +// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe // * Our custom AssertUnwindSafe wrapper is indeed unwind safe #[stable(feature = "catch_unwind", since = "1.9.0")] diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index f3b1185c6ea..df1dd7401af 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -236,7 +236,7 @@ enum State { impl<'a> AsyncPipe<'a> { fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> { // Create an event which we'll use to coordinate our overlapped - // opreations, this event will be used in WaitForMultipleObjects + // operations, this event will be used in WaitForMultipleObjects // and passed as part of the OVERLAPPED handle. // // Note that we do a somewhat clever thing here by flagging the diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 31bb1c88b87..9d0c85a34f9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2192,6 +2192,8 @@ pub enum ForeignItemKind { Static(P<Ty>, bool), /// A foreign type Ty, + /// A macro invocation + Macro(Mac), } impl ForeignItemKind { @@ -2200,6 +2202,7 @@ impl ForeignItemKind { ForeignItemKind::Fn(..) => "foreign function", ForeignItemKind::Static(..) => "foreign static item", ForeignItemKind::Ty => "foreign type", + ForeignItemKind::Macro(..) => "macro in foreign module", } } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d3157af984e..5a735be55c0 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -38,6 +38,7 @@ pub enum Annotatable { Item(P<ast::Item>), TraitItem(P<ast::TraitItem>), ImplItem(P<ast::ImplItem>), + ForeignItem(P<ast::ForeignItem>), Stmt(P<ast::Stmt>), Expr(P<ast::Expr>), } @@ -48,6 +49,7 @@ impl HasAttrs for Annotatable { Annotatable::Item(ref item) => &item.attrs, Annotatable::TraitItem(ref trait_item) => &trait_item.attrs, Annotatable::ImplItem(ref impl_item) => &impl_item.attrs, + Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs, Annotatable::Stmt(ref stmt) => stmt.attrs(), Annotatable::Expr(ref expr) => &expr.attrs, } @@ -58,6 +60,8 @@ impl HasAttrs for Annotatable { Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)), Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)), Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)), + Annotatable::ForeignItem(foreign_item) => + Annotatable::ForeignItem(foreign_item.map_attrs(f)), Annotatable::Stmt(stmt) => Annotatable::Stmt(stmt.map_attrs(f)), Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)), } @@ -70,6 +74,7 @@ impl Annotatable { Annotatable::Item(ref item) => item.span, Annotatable::TraitItem(ref trait_item) => trait_item.span, Annotatable::ImplItem(ref impl_item) => impl_item.span, + Annotatable::ForeignItem(ref foreign_item) => foreign_item.span, Annotatable::Stmt(ref stmt) => stmt.span, Annotatable::Expr(ref expr) => expr.span, } @@ -106,6 +111,13 @@ impl Annotatable { } } + pub fn expect_foreign_item(self) -> ast::ForeignItem { + match self { + Annotatable::ForeignItem(i) => i.into_inner(), + _ => panic!("expected foreign item") + } + } + pub fn derive_allowed(&self) -> bool { match *self { Annotatable::Item(ref item) => match item.node { @@ -317,6 +329,9 @@ pub trait MacResult { None } + /// Create zero or more items in an `extern {}` block + fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { None } + /// Create a pattern. fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { None @@ -365,6 +380,7 @@ make_MacEager! { items: SmallVector<P<ast::Item>>, impl_items: SmallVector<ast::ImplItem>, trait_items: SmallVector<ast::TraitItem>, + foreign_items: SmallVector<ast::ForeignItem>, stmts: SmallVector<ast::Stmt>, ty: P<ast::Ty>, } @@ -386,6 +402,10 @@ impl MacResult for MacEager { self.trait_items } + fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { + self.foreign_items + } + fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> { match self.stmts.as_ref().map_or(0, |s| s.len()) { 0 => make_stmts_default!(self), @@ -502,6 +522,14 @@ impl MacResult for DummyResult { } } + fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { + if self.expr_only { + None + } else { + Some(SmallVector::new()) + } + } + fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<ast::Stmt>> { Some(SmallVector::one(ast::Stmt { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 864969c4075..105de13b976 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -133,6 +133,8 @@ expansions! { "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item; ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem], "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item; + ForeignItems: SmallVector<ast::ForeignItem> [SmallVector, ast::ForeignItem], + "foreign item", .make_foreign_items, lift .fold_foreign_item, lift .visit_foreign_item; } impl ExpansionKind { @@ -149,6 +151,8 @@ impl ExpansionKind { Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()), ExpansionKind::TraitItems => Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()), + ExpansionKind::ForeignItems => + Expansion::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()), _ => unreachable!(), } } @@ -435,6 +439,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::ImplItem(item) => { Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap())) } + Annotatable::ForeignItem(item) => { + Annotatable::ForeignItem( + item.map(|item| cfg.fold_foreign_item(item).pop().unwrap()) + ) + } Annotatable::Stmt(stmt) => { Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap())) } @@ -509,6 +518,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Item(item) => token::NtItem(item), Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()), + Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), Annotatable::Expr(expr) => token::NtExpr(expr), })).into(); @@ -793,6 +803,15 @@ impl<'a> Parser<'a> { } Expansion::ImplItems(items) } + ExpansionKind::ForeignItems => { + let mut items = SmallVector::new(); + while self.token != token::Eof { + if let Some(item) = self.parse_foreign_item()? { + items.push(item); + } + } + Expansion::ForeignItems(items) + } ExpansionKind::Stmts => { let mut stmts = SmallVector::new(); while self.token != token::Eof && @@ -1166,6 +1185,44 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self) } + fn fold_foreign_item(&mut self, + foreign_item: ast::ForeignItem) -> SmallVector<ast::ForeignItem> { + let (attr, traits, foreign_item) = self.classify_item(foreign_item); + + let explain = if self.cx.ecfg.proc_macro_enabled() { + feature_gate::EXPLAIN_PROC_MACROS_IN_EXTERN + } else { + feature_gate::EXPLAIN_MACROS_IN_EXTERN + }; + + if attr.is_some() || !traits.is_empty() { + if !self.cx.ecfg.macros_in_extern_enabled() { + if let Some(ref attr) = attr { + emit_feature_err(&self.cx.parse_sess, "macros_in_extern", attr.span, + GateIssue::Language, explain); + } + } + + let item = Annotatable::ForeignItem(P(foreign_item)); + return self.collect_attr(attr, traits, item, ExpansionKind::ForeignItems) + .make_foreign_items(); + } + + if let ast::ForeignItemKind::Macro(mac) = foreign_item.node { + self.check_attributes(&foreign_item.attrs); + + if !self.cx.ecfg.macros_in_extern_enabled() { + emit_feature_err(&self.cx.parse_sess, "macros_in_extern", foreign_item.span, + GateIssue::Language, explain); + } + + return self.collect_bang(mac, foreign_item.span, ExpansionKind::ForeignItems) + .make_foreign_items(); + } + + noop_fold_foreign_item(foreign_item, self) + } + fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { match item { ast::ItemKind::MacroDef(..) => item, @@ -1311,6 +1368,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = custom_derive, fn proc_macro_enabled = proc_macro, + fn macros_in_extern_enabled = macros_in_extern, } } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 9c2c22476e9..9f60882ca29 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -60,6 +60,10 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { defaultness: ast::Defaultness::Final, tokens: None, })), + ExpansionKind::ForeignItems => Expansion::ForeignItems(SmallVector::one(ast::ForeignItem { + id, span, ident, vis, attrs, + node: ast::ForeignItemKind::Macro(mac_placeholder()), + })), ExpansionKind::Pat => Expansion::Pat(P(ast::Pat { id, span, node: ast::PatKind::Mac(mac_placeholder()), })), @@ -132,6 +136,13 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { } } + fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVector<ast::ForeignItem> { + match item.node { + ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(), + _ => noop_fold_foreign_item(item, self), + } + } + fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> { match expr.node { ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0f039895dee..9d1f4ccf8a3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -443,6 +443,9 @@ declare_features! ( // Allows keywords to be escaped for use as identifiers (active, raw_identifiers, "1.26.0", Some(48589), None), + + // Allows macro invocations in `extern {}` blocks + (active, macros_in_extern, "1.27.0", Some(49476), None), ); declare_features! ( @@ -1291,6 +1294,13 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str = "Using the `?` macro Kleene operator for \"at most one\" repetition is unstable"; +pub const EXPLAIN_MACROS_IN_EXTERN: &'static str = + "Macro invocations in `extern {}` blocks are experimental."; + +// mention proc-macros when enabled +pub const EXPLAIN_PROC_MACROS_IN_EXTERN: &'static str = + "Macro and proc-macro invocations in `extern {}` blocks are experimental."; + struct PostExpansionVisitor<'a> { context: &'a Context<'a>, } @@ -1595,6 +1605,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); } + ast::ForeignItemKind::Macro(..) => {} } visit::walk_foreign_item(self, i) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index e702bf56e7f..1bee67bf360 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -60,10 +60,14 @@ pub trait Folder : Sized { noop_fold_use_tree(use_tree, self) } - fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem { + fn fold_foreign_item(&mut self, ni: ForeignItem) -> SmallVector<ForeignItem> { noop_fold_foreign_item(ni, self) } + fn fold_foreign_item_simple(&mut self, ni: ForeignItem) -> ForeignItem { + noop_fold_foreign_item_simple(ni, self) + } + fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> { noop_fold_item(i, self) } @@ -414,7 +418,7 @@ pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod, fld: &mut T) -> ForeignMod { ForeignMod { abi, - items: items.move_map(|x| fld.fold_foreign_item(x)), + items: items.move_flat_map(|x| fld.fold_foreign_item(x)), } } @@ -648,6 +652,10 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T) token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)), token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)), token::NtLifetime(lifetime) => token::NtLifetime(fld.fold_lifetime(lifetime)), + token::NtForeignItem(ni) => + token::NtForeignItem(fld.fold_foreign_item(ni) + // see reasoning above + .expect_one("expected fold to produce exactly one item")), } } @@ -1072,7 +1080,12 @@ pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span, } } -pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem { +pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) +-> SmallVector<ForeignItem> { + SmallVector::one(folder.fold_foreign_item_simple(ni)) +} + +pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem { ForeignItem { id: folder.new_id(ni.id), vis: folder.fold_vis(ni.vis), @@ -1086,6 +1099,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For ForeignItemKind::Static(folder.fold_ty(t), m) } ForeignItemKind::Ty => ForeignItemKind::Ty, + ForeignItemKind::Macro(mac) => ForeignItemKind::Macro(folder.fold_mac(mac)), }, span: folder.new_span(ni.span) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f5ab023b30e..9936eea9356 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -26,7 +26,7 @@ use ast::{Ident, ImplItem, IsAuto, Item, ItemKind}; use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::Local; use ast::MacStmtStyle; -use ast::Mac_; +use ast::{Mac, Mac_}; use ast::{MutTy, Mutability}; use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; @@ -1417,28 +1417,8 @@ impl<'a> Parser<'a> { None }; (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) - } else if self.token.is_path_start() && !self.is_extern_non_path() { + } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { // trait item macro. - // code copied from parse_macro_use_or_failure... abstraction! - let prev_span = self.prev_span; - let lo = self.span; - let pth = self.parse_path(PathStyle::Mod)?; - - if pth.segments.len() == 1 { - if !self.eat(&token::Not) { - return Err(self.missing_assoc_item_kind_err("trait", prev_span)); - } - } else { - self.expect(&token::Not)?; - } - - // eat a matched-delimiter token tree: - let (delim, tts) = self.expect_delimited_token_tree()?; - if delim != token::Brace { - self.expect(&token::Semi)? - } - - let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) } else { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; @@ -5393,6 +5373,12 @@ impl<'a> Parser<'a> { fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span) -> DiagnosticBuilder<'a> { + let expected_kinds = if item_type == "extern" { + "missing `fn`, `type`, or `static`" + } else { + "missing `fn`, `type`, or `const`" + }; + // Given this code `path(`, it seems like this is not // setting the visibility of a macro invocation, but rather // a mistyped method declaration. @@ -5405,9 +5391,9 @@ impl<'a> Parser<'a> { let sp = prev_span.between(self.prev_span); let mut err = self.diagnostic().struct_span_err( sp, - &format!("missing `fn`, `type`, or `const` for {}-item declaration", - item_type)); - err.span_label(sp, "missing `fn`, `type`, or `const`"); + &format!("{} for {}-item declaration", + expected_kinds, item_type)); + err.span_label(sp, expected_kinds); err } @@ -5416,31 +5402,8 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec<Attribute>, ast::Generics, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! - if self.token.is_path_start() && !self.is_extern_non_path() { + if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { // Method macro. - - let prev_span = self.prev_span; - - let lo = self.span; - let pth = self.parse_path(PathStyle::Mod)?; - if pth.segments.len() == 1 { - if !self.eat(&token::Not) { - return Err(self.missing_assoc_item_kind_err("impl", prev_span)); - } - } else { - self.expect(&token::Not)?; - } - - self.complain_if_pub_macro(&vis.node, prev_span); - - // eat a matched-delimiter token tree: - *at_end = true; - let (delim, tts) = self.expect_delimited_token_tree()?; - if delim != token::Brace { - self.expect(&token::Semi)? - } - - let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(), ast::ImplItemKind::Macro(mac))) } else { @@ -6786,7 +6749,9 @@ impl<'a> Parser<'a> { } /// Parse a foreign item. - fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> { + pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> { + maybe_whole!(self, NtForeignItem, |ni| Some(ni)); + let attrs = self.parse_outer_attributes()?; let lo = self.span; let visibility = self.parse_visibility(false)?; @@ -6812,12 +6777,26 @@ impl<'a> Parser<'a> { return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?)); } - // FIXME #5668: this will occur for a macro invocation: - match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? { - Some(item) => { - return Err(self.span_fatal(item.span, "macros cannot expand to foreign items")); + match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { + Some(mac) => { + Ok(Some( + ForeignItem { + ident: keywords::Invalid.ident(), + span: lo.to(self.prev_span), + id: ast::DUMMY_NODE_ID, + attrs, + vis: visibility, + node: ForeignItemKind::Macro(mac), + } + )) + } + None => { + if !attrs.is_empty() { + self.expected_item_err(&attrs); + } + + Ok(None) } - None => Ok(None) } } @@ -6881,6 +6860,41 @@ impl<'a> Parser<'a> { Ok(None) } + /// Parse a macro invocation inside a `trait`, `impl` or `extern` block + fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>, + at_end: &mut bool) -> PResult<'a, Option<Mac>> + { + if self.token.is_path_start() && !self.is_extern_non_path() { + let prev_span = self.prev_span; + let lo = self.span; + let pth = self.parse_path(PathStyle::Mod)?; + + if pth.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err(item_kind, prev_span)); + } + } else { + self.expect(&token::Not)?; + } + + if let Some(vis) = vis { + self.complain_if_pub_macro(&vis.node, prev_span); + } + + *at_end = true; + + // eat a matched-delimiter token tree: + let (delim, tts) = self.expect_delimited_token_tree()?; + if delim != token::Brace { + self.expect(&token::Semi)? + } + + Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }))) + } else { + Ok(None) + } + } + fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)> where F: FnOnce(&mut Self) -> PResult<'a, R> { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index e2dfca5d10a..5fe2b081566 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -581,6 +581,7 @@ pub enum Nonterminal { NtArm(ast::Arm), NtImplItem(ast::ImplItem), NtTraitItem(ast::TraitItem), + NtForeignItem(ast::ForeignItem), NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), NtArg(ast::Arg), @@ -603,6 +604,7 @@ impl fmt::Debug for Nonterminal { NtArm(..) => f.pad("NtArm(..)"), NtImplItem(..) => f.pad("NtImplItem(..)"), NtTraitItem(..) => f.pad("NtTraitItem(..)"), + NtForeignItem(..) => f.pad("NtForeignItem(..)"), NtGenerics(..) => f.pad("NtGenerics(..)"), NtWhereClause(..) => f.pad("NtWhereClause(..)"), NtArg(..) => f.pad("NtArg(..)"), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c3785c10f69..1bed6109dd2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -281,6 +281,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtArg(ref e) => arg_to_string(e), token::NtVis(ref e) => vis_to_string(e), token::NtLifetime(ref e) => lifetime_to_string(e), + token::NtForeignItem(ref ni) => foreign_item_to_string(ni), } } } @@ -422,6 +423,10 @@ pub fn mac_to_string(arg: &ast::Mac) -> String { to_string(|s| s.print_mac(arg, ::parse::token::Paren)) } +pub fn foreign_item_to_string(arg: &ast::ForeignItem) -> String { + to_string(|s| s.print_foreign_item(arg)) +} + pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { format!("{}{}", to_string(|s| s.print_visibility(vis)), s) } @@ -1127,6 +1132,10 @@ impl<'a> State<'a> { self.end()?; // end the head-ibox self.end() // end the outer cbox } + ast::ForeignItemKind::Macro(ref m) => { + self.print_mac(m, token::Paren)?; + self.s.word(";") + } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index d8de78054ab..3a2069efd89 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -460,6 +460,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a } ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), ForeignItemKind::Ty => (), + ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), } walk_list!(visitor, visit_attribute, &foreign_item.attrs); diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 80557078d54..5fd5e299488 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -55,6 +55,7 @@ impl MultiItemModifier for ProcMacroDerive { Annotatable::Item(item) => item, Annotatable::ImplItem(_) | Annotatable::TraitItem(_) | + Annotatable::ForeignItem(_) | Annotatable::Stmt(_) | Annotatable::Expr(_) => { ecx.span_err(span, "proc-macro derives may only be \ diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index 77ea3019419..bc51b4061ed 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -93,7 +93,9 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, } }) } - // these are covered in proc_macro/attr-stmt-expr.rs + // covered in proc_macro/macros-in-extern.rs + Annotatable::ForeignItem(_) => unimplemented!(), + // covered in proc_macro/attr-stmt-expr.rs Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item") } } @@ -147,6 +149,8 @@ fn expand_duplicate(cx: &mut ExtCtxt, new_it.ident = copy_name; push(Annotatable::TraitItem(P(new_it))); } + // covered in proc_macro/macros-in-extern.rs + Annotatable::ForeignItem(_) => unimplemented!(), // covered in proc_macro/attr-stmt-expr.rs Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item") } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs index d725adfec75..bbfec5815ba 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs @@ -16,7 +16,7 @@ extern crate proc_macro; -use proc_macro::{TokenStream, TokenTree, TokenNode, Delimiter, Literal, Spacing}; +use proc_macro::{TokenStream, TokenTree, Delimiter, Literal, Spacing, Group}; #[proc_macro_attribute] pub fn foo(attr: TokenStream, input: TokenStream) -> TokenStream { @@ -52,24 +52,30 @@ pub fn bar(attr: TokenStream, input: TokenStream) -> TokenStream { } fn assert_inline(slice: &mut &[TokenTree]) { - match slice[0].kind { - TokenNode::Op('#', _) => {} + match &slice[0] { + TokenTree::Op(tt) => assert_eq!(tt.op(), '#'), _ => panic!("expected '#' char"), } - match slice[1].kind { - TokenNode::Group(Delimiter::Bracket, _) => {} + match &slice[1] { + TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket), _ => panic!("expected brackets"), } *slice = &slice[2..]; } fn assert_doc(slice: &mut &[TokenTree]) { - match slice[0].kind { - TokenNode::Op('#', Spacing::Alone) => {} + match &slice[0] { + TokenTree::Op(tt) => { + assert_eq!(tt.op(), '#'); + assert_eq!(tt.spacing(), Spacing::Alone); + } _ => panic!("expected #"), } - let inner = match slice[1].kind { - TokenNode::Group(Delimiter::Bracket, ref s) => s.clone(), + let inner = match &slice[1] { + TokenTree::Group(tt) => { + assert_eq!(tt.delimiter(), Delimiter::Bracket); + tt.stream() + } _ => panic!("expected brackets"), }; let tokens = inner.into_iter().collect::<Vec<_>>(); @@ -79,16 +85,19 @@ fn assert_doc(slice: &mut &[TokenTree]) { panic!("expected three tokens in doc") } - match tokens[0].kind { - TokenNode::Term(ref t) => assert_eq!("doc", t.as_str()), + match &tokens[0] { + TokenTree::Term(tt) => assert_eq!("doc", tt.as_str()), _ => panic!("expected `doc`"), } - match tokens[1].kind { - TokenNode::Op('=', Spacing::Alone) => {} + match &tokens[1] { + TokenTree::Op(tt) => { + assert_eq!(tt.op(), '='); + assert_eq!(tt.spacing(), Spacing::Alone); + } _ => panic!("expected equals"), } - match tokens[2].kind { - TokenNode::Literal(_) => {} + match tokens[2] { + TokenTree::Literal(_) => {} _ => panic!("expected literal"), } @@ -96,32 +105,35 @@ fn assert_doc(slice: &mut &[TokenTree]) { } fn assert_invoc(slice: &mut &[TokenTree]) { - match slice[0].kind { - TokenNode::Op('#', _) => {} + match &slice[0] { + TokenTree::Op(tt) => assert_eq!(tt.op(), '#'), _ => panic!("expected '#' char"), } - match slice[1].kind { - TokenNode::Group(Delimiter::Bracket, _) => {} + match &slice[1] { + TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket), _ => panic!("expected brackets"), } *slice = &slice[2..]; } fn assert_foo(slice: &mut &[TokenTree]) { - match slice[0].kind { - TokenNode::Term(ref name) => assert_eq!(name.as_str(), "fn"), + match &slice[0] { + TokenTree::Term(tt) => assert_eq!(tt.as_str(), "fn"), _ => panic!("expected fn"), } - match slice[1].kind { - TokenNode::Term(ref name) => assert_eq!(name.as_str(), "foo"), + match &slice[1] { + TokenTree::Term(tt) => assert_eq!(tt.as_str(), "foo"), _ => panic!("expected foo"), } - match slice[2].kind { - TokenNode::Group(Delimiter::Parenthesis, ref s) => assert!(s.is_empty()), + match &slice[2] { + TokenTree::Group(tt) => { + assert_eq!(tt.delimiter(), Delimiter::Parenthesis); + assert!(tt.stream().is_empty()); + } _ => panic!("expected parens"), } - match slice[3].kind { - TokenNode::Group(Delimiter::Brace, _) => {} + match &slice[3] { + TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Brace), _ => panic!("expected braces"), } *slice = &slice[4..]; @@ -132,22 +144,17 @@ fn fold_stream(input: TokenStream) -> TokenStream { } fn fold_tree(input: TokenTree) -> TokenTree { - TokenTree { - span: input.span, - kind: fold_node(input.kind), - } -} - -fn fold_node(input: TokenNode) -> TokenNode { match input { - TokenNode::Group(a, b) => TokenNode::Group(a, fold_stream(b)), - TokenNode::Op(a, b) => TokenNode::Op(a, b), - TokenNode::Term(a) => TokenNode::Term(a), - TokenNode::Literal(a) => { + TokenTree::Group(b) => { + TokenTree::Group(Group::new(b.delimiter(), fold_stream(b.stream()))) + } + TokenTree::Op(b) => TokenTree::Op(b), + TokenTree::Term(a) => TokenTree::Term(a), + TokenTree::Literal(a) => { if a.to_string() != "\"foo\"" { - TokenNode::Literal(a) + TokenTree::Literal(a) } else { - TokenNode::Literal(Literal::integer(3)) + TokenTree::Literal(Literal::i32_unsuffixed(3)) } } } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs new file mode 100644 index 00000000000..d1c5b9050aa --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs @@ -0,0 +1,36 @@ +// 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"] +#![feature(proc_macro)] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream { + assert!(_attr.to_string().is_empty()); + input +} + +#[proc_macro_attribute] +pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream { + assert!(_attr.to_string().is_empty()); + assert!(!_input.to_string().is_empty()); + "".parse().unwrap() +} + +#[proc_macro] +pub fn emit_input(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs new file mode 100644 index 00000000000..4c88df33246 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs @@ -0,0 +1,38 @@ +// 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:test-macros.rs +// ignore-stage1 +// ignore-wasm32 + +#![feature(proc_macro)] + +extern crate test_macros; + +use test_macros::{nop_attr, no_output, emit_input}; + +fn main() { + assert_eq!(unsafe { rust_get_test_int() }, 0isize); + assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + #[no_output] + //~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental. + fn some_definitely_unknown_symbol_which_should_be_removed(); + + #[nop_attr] + //~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental. + fn rust_get_test_int() -> isize; + + emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); + //~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental. +} diff --git a/src/test/compile-fail/macros-in-extern.rs b/src/test/compile-fail/macros-in-extern.rs new file mode 100644 index 00000000000..7d7f95cbbf5 --- /dev/null +++ b/src/test/compile-fail/macros-in-extern.rs @@ -0,0 +1,42 @@ +// 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. + +// ignore-wasm32 + +#![feature(decl_macro)] + +macro_rules! returns_isize( + ($ident:ident) => ( + fn $ident() -> isize; + ) +); + +macro takes_u32_returns_u32($ident:ident) { + fn $ident (arg: u32) -> u32; +} + +macro_rules! emits_nothing( + () => () +); + +fn main() { + assert_eq!(unsafe { rust_get_test_int() }, 0isize); + assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + returns_isize!(rust_get_test_int); + //~^ ERROR Macro invocations in `extern {}` blocks are experimental. + takes_u32_returns_u32!(rust_dbg_extern_identity_u32); + //~^ ERROR Macro invocations in `extern {}` blocks are experimental. + emits_nothing!(); + //~^ ERROR Macro invocations in `extern {}` blocks are experimental. +} diff --git a/src/test/parse-fail/duplicate-visibility.rs b/src/test/parse-fail/duplicate-visibility.rs index 5ee84cd5543..6899caa7153 100644 --- a/src/test/parse-fail/duplicate-visibility.rs +++ b/src/test/parse-fail/duplicate-visibility.rs @@ -10,7 +10,7 @@ // compile-flags: -Z parse-only -// error-pattern:unmatched visibility `pub` +// error-pattern:expected one of `(`, `fn`, `static`, `type`, or `}` here extern { pub pub fn foo(); } diff --git a/src/test/parse-fail/extern-no-fn.rs b/src/test/parse-fail/extern-no-fn.rs index ff3fefde40e..aa0dbd4d4fc 100644 --- a/src/test/parse-fail/extern-no-fn.rs +++ b/src/test/parse-fail/extern-no-fn.rs @@ -10,8 +10,8 @@ // compile-flags: -Z parse-only -extern { - f(); //~ ERROR expected one of `!` or `::`, found `(` +extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration + f(); } fn main() { diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs index e2c68a626f9..281ee70815e 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs @@ -15,15 +15,15 @@ extern crate proc_macro; -use proc_macro::{TokenStream, TokenNode, quote}; +use proc_macro::*; #[proc_macro] pub fn cond(input: TokenStream) -> TokenStream { let mut conds = Vec::new(); let mut input = input.into_iter().peekable(); while let Some(tree) = input.next() { - let cond = match tree.kind { - TokenNode::Group(_, cond) => cond, + let cond = match tree { + TokenTree::Group(tt) => tt.stream(), _ => panic!("Invalid input"), }; let mut cond_trees = cond.clone().into_iter(); @@ -32,8 +32,8 @@ pub fn cond(input: TokenStream) -> TokenStream { if rhs.is_empty() { panic!("Invalid macro usage in cond: {}", cond); } - let is_else = match test.kind { - TokenNode::Term(word) => word.as_str() == "else", + let is_else = match test { + TokenTree::Term(word) => word.as_str() == "else", _ => false, }; conds.push(if is_else || input.peek().is_none() { @@ -43,5 +43,5 @@ pub fn cond(input: TokenStream) -> TokenStream { }); } - conds.into_iter().collect() + conds.into_iter().flat_map(|x| x.into_iter()).collect() } diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 5ebd3292132..6612fe45b81 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -96,7 +96,9 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, } }) ], - // these are covered in proc_macro/attr-stmt-expr.rs + // covered in proc_macro/macros-in-extern.rs + Annotatable::ForeignItem(..) => unimplemented!(), + // covered in proc_macro/attr-stmt-expr.rs Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item"), } } @@ -142,7 +144,9 @@ fn expand_duplicate(cx: &mut ExtCtxt, new_it.ident = copy_name; push(Annotatable::TraitItem(P(new_it))); } - // these are covered in proc_macro/attr-stmt-expr.rs + // covered in proc_macro/macros-in-extern.rs + Annotatable::ForeignItem(..) => unimplemented!(), + // covered in proc_macro/attr-stmt-expr.rs Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item") } } diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs index 1b470438848..d3670ae66fe 100644 --- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs +++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs @@ -15,7 +15,7 @@ extern crate proc_macro; -use proc_macro::{TokenStream, quote}; +use proc_macro::*; #[proc_macro_attribute] pub fn attr_tru(_attr: TokenStream, item: TokenStream) -> TokenStream { diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs index ec2ff0d1e2b..063d8dc4053 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs @@ -15,20 +15,25 @@ extern crate proc_macro; -use proc_macro::{TokenStream, TokenNode, Spacing, Literal, quote}; +use proc_macro::{TokenStream, TokenTree, Spacing, Literal, quote}; #[proc_macro] pub fn count_compound_ops(input: TokenStream) -> TokenStream { assert_eq!(count_compound_ops_helper(quote!(++ (&&) 4@a)), 3); - TokenNode::Literal(Literal::u32(count_compound_ops_helper(input))).into() + let l = Literal::u32_suffixed(count_compound_ops_helper(input)); + TokenTree::from(l).into() } fn count_compound_ops_helper(input: TokenStream) -> u32 { let mut count = 0; for token in input { - match token.kind { - TokenNode::Op(c, Spacing::Alone) => count += 1, - TokenNode::Group(_, tokens) => count += count_compound_ops_helper(tokens), + match &token { + TokenTree::Op(tt) if tt.spacing() == Spacing::Alone => { + count += 1; + } + TokenTree::Group(tt) => { + count += count_compound_ops_helper(tt.stream()); + } _ => {} } } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs index e5ebb7c2e41..e76e4d585f4 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs @@ -19,16 +19,10 @@ use proc_macro::*; #[proc_macro] pub fn neg_one(_input: TokenStream) -> TokenStream { - TokenTree { - span: Span::call_site(), - kind: TokenNode::Literal(Literal::i32(-1)), - }.into() + TokenTree::Literal(Literal::i32_suffixed(-1)).into() } #[proc_macro] pub fn neg_one_float(_input: TokenStream) -> TokenStream { - TokenTree { - span: Span::call_site(), - kind: TokenNode::Literal(Literal::f32(-1.0)), - }.into() + TokenTree::Literal(Literal::f32_suffixed(-1.0)).into() } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs index ce6ffcc3cb0..6ab9d6d0b8a 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs @@ -27,7 +27,7 @@ pub fn reemit(input: TokenStream) -> TokenStream { #[proc_macro] pub fn assert_fake_source_file(input: TokenStream) -> TokenStream { for tk in input { - let source_file = tk.span.source_file(); + let source_file = tk.span().source_file(); assert!(!source_file.is_real(), "Source file is real: {:?}", source_file); } @@ -37,7 +37,7 @@ pub fn assert_fake_source_file(input: TokenStream) -> TokenStream { #[proc_macro] pub fn assert_source_file(input: TokenStream) -> TokenStream { for tk in input { - let source_file = tk.span.source_file(); + let source_file = tk.span().source_file(); assert!(source_file.is_real(), "Source file is not real: {:?}", source_file); } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs new file mode 100644 index 00000000000..d1c5b9050aa --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs @@ -0,0 +1,36 @@ +// 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"] +#![feature(proc_macro)] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream { + assert!(_attr.to_string().is_empty()); + input +} + +#[proc_macro_attribute] +pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream { + assert!(_attr.to_string().is_empty()); + assert!(!_input.to_string().is_empty()); + "".parse().unwrap() +} + +#[proc_macro] +pub fn emit_input(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs new file mode 100644 index 00000000000..59b9b0baa8a --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs @@ -0,0 +1,35 @@ +// 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:test-macros.rs +// ignore-stage1 +// ignore-wasm32 + +#![feature(proc_macro, macros_in_extern)] + +extern crate test_macros; + +use test_macros::{nop_attr, no_output, emit_input}; + +fn main() { + assert_eq!(unsafe { rust_get_test_int() }, 1isize); + assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + #[no_output] + fn some_definitely_unknown_symbol_which_should_be_removed(); + + #[nop_attr] + fn rust_get_test_int() -> isize; + + emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); +} diff --git a/src/test/run-pass/macros-in-extern.rs b/src/test/run-pass/macros-in-extern.rs new file mode 100644 index 00000000000..d9094934356 --- /dev/null +++ b/src/test/run-pass/macros-in-extern.rs @@ -0,0 +1,39 @@ +// 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. + +// ignore-wasm32 + +#![feature(decl_macro, macros_in_extern)] + +macro_rules! returns_isize( + ($ident:ident) => ( + fn $ident() -> isize; + ) +); + +macro takes_u32_returns_u32($ident:ident) { + fn $ident (arg: u32) -> u32; +} + +macro_rules! emits_nothing( + () => () +); + +fn main() { + assert_eq!(unsafe { rust_get_test_int() }, 1isize); + assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + returns_isize!(rust_get_test_int); + takes_u32_returns_u32!(rust_dbg_extern_identity_u32); + emits_nothing!(); +} diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs index 3eb96c2ab96..ed11b2db2f5 100644 --- a/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs @@ -14,12 +14,12 @@ extern crate proc_macro; -use proc_macro::{TokenStream, TokenTree, TokenNode, Span}; +use proc_macro::{TokenStream, TokenTree, Span}; fn lit_span(tt: TokenTree) -> (Span, String) { - use TokenNode::*; - match tt.kind { - Literal(..) | Group(..) => (tt.span, tt.to_string().trim().into()), + match tt { + TokenTree::Literal(..) | + TokenTree::Group(..) => (tt.span(), tt.to_string().trim().into()), _ => panic!("expected a literal in token tree, got: {:?}", tt) } } diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs index 2381c61b87b..fda0e28891f 100644 --- a/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs @@ -14,26 +14,27 @@ extern crate proc_macro; -use proc_macro::{TokenStream, TokenNode, Span, Diagnostic}; +use proc_macro::{TokenStream, TokenTree, Span, Diagnostic}; fn parse(input: TokenStream) -> Result<(), Diagnostic> { let mut count = 0; let mut last_span = Span::def_site(); for tree in input { - let span = tree.span; + let span = tree.span(); if count >= 3 { return Err(span.error(format!("expected EOF, found `{}`.", tree)) .span_note(last_span, "last good input was here") .help("input must be: `===`")) } - if let TokenNode::Op('=', _) = tree.kind { - count += 1; - } else { - return Err(span.error(format!("expected `=`, found `{}`.", tree))); + if let TokenTree::Op(tt) = tree { + if tt.op() == '=' { + count += 1; + last_span = span; + continue + } } - - last_span = span; + return Err(span.error(format!("expected `=`, found `{}`.", tree))); } if count < 3 { diff --git a/src/test/ui/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gate-macros_in_extern.rs new file mode 100644 index 00000000000..9c758241ea1 --- /dev/null +++ b/src/test/ui/feature-gate-macros_in_extern.rs @@ -0,0 +1,35 @@ +// 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)] + +macro_rules! returns_isize( + ($ident:ident) => ( + fn $ident() -> isize; + ) +); + +macro takes_u32_returns_u32($ident:ident) { + fn $ident (arg: u32) -> u32; +} + +macro_rules! emits_nothing( + () => () +); + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + returns_isize!(rust_get_test_int); + //~^ ERROR Macro invocations in `extern {}` blocks are experimental. + takes_u32_returns_u32!(rust_dbg_extern_identity_u32); + //~^ ERROR Macro invocations in `extern {}` blocks are experimental. + emits_nothing!(); + //~^ ERROR Macro invocations in `extern {}` blocks are experimental. +} diff --git a/src/test/ui/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gate-macros_in_extern.stderr new file mode 100644 index 00000000000..49aca0db2d4 --- /dev/null +++ b/src/test/ui/feature-gate-macros_in_extern.stderr @@ -0,0 +1,27 @@ +error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476) + --> $DIR/feature-gate-macros_in_extern.rs:29:5 + | +LL | returns_isize!(rust_get_test_int); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(macros_in_extern)] to the crate attributes to enable + +error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476) + --> $DIR/feature-gate-macros_in_extern.rs:31:5 + | +LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(macros_in_extern)] to the crate attributes to enable + +error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476) + --> $DIR/feature-gate-macros_in_extern.rs:33:5 + | +LL | emits_nothing!(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(macros_in_extern)] to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 49b054f8b9e..0f482c95e05 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -356,6 +356,28 @@ impl Builder { target: "*".to_string(), }); + // If the components/extensions don't actually exist for this + // particular host/target combination then nix it entirely from our + // lists. + { + let has_component = |c: &Component| { + if c.target == "*" { + return true + } + let pkg = match manifest.pkg.get(&c.pkg) { + Some(p) => p, + None => return false, + }; + let target = match pkg.target.get(&c.target) { + Some(t) => t, + None => return false, + }; + target.available + }; + extensions.retain(&has_component); + components.retain(&has_component); + } + pkg.target.insert(host.to_string(), Target { available: true, url: Some(self.url(&filename)), |
