93 changes: 52 additions & 41 deletions src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ ast_enum_of_structs! {
/// A Rust expression.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
/// feature, but most of the variants are not available unless "full" is enabled.*
///
/// # Syntax tree enums
///
Expand Down Expand Up @@ -1210,9 +1210,12 @@ pub(crate) fn requires_terminator(expr: &Expr) -> bool {
pub(crate) mod parsing {
use super::*;

use crate::parse::discouraged::Speculative;
use crate::parse::{Parse, ParseStream, Result};
use crate::path;

crate::custom_keyword!(raw);

// When we're parsing expressions which occur before blocks, like in an if
// statement's condition, we cannot parse a struct literal.
//
Expand Down Expand Up @@ -1465,24 +1468,41 @@ pub(crate) mod parsing {
// box <trailer>
#[cfg(feature = "full")]
fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
// TODO: optimize using advance_to
let begin = input.fork();
let ahead = input.fork();
ahead.call(Attribute::parse_outer)?;
let attrs = ahead.call(Attribute::parse_outer)?;
if ahead.peek(Token![&])
|| ahead.peek(Token![box])
|| ahead.peek(Token![*])
|| ahead.peek(Token![!])
|| ahead.peek(Token![-])
{
let attrs = input.call(Attribute::parse_outer)?;
input.advance_to(&ahead);
if input.peek(Token![&]) {
Ok(Expr::Reference(ExprReference {
attrs,
and_token: input.parse()?,
raw: Reserved::default(),
mutability: input.parse()?,
expr: Box::new(unary_expr(input, allow_struct)?),
}))
let and_token: Token![&] = input.parse()?;
let raw: Option<raw> = if input.peek(raw)
&& (input.peek2(Token![mut]) || input.peek2(Token![const]))
{
Some(input.parse()?)
} else {
None
};
let mutability: Option<Token![mut]> = input.parse()?;
if raw.is_some() && mutability.is_none() {
input.parse::<Token![const]>()?;
}
let expr = Box::new(unary_expr(input, allow_struct)?);
if raw.is_some() {
Ok(Expr::Verbatim(verbatim::between(begin, input)))
} else {
Ok(Expr::Reference(ExprReference {
attrs,
and_token,
raw: Reserved::default(),
mutability,
expr,
}))
}
} else if input.peek(Token![box]) {
Ok(Expr::Box(ExprBox {
attrs,
Expand All @@ -1503,12 +1523,12 @@ pub(crate) mod parsing {

#[cfg(not(feature = "full"))]
fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
// TODO: optimize using advance_to
let ahead = input.fork();
ahead.call(Attribute::parse_outer)?;
let attrs = ahead.call(Attribute::parse_outer)?;
if ahead.peek(Token![*]) || ahead.peek(Token![!]) || ahead.peek(Token![-]) {
input.advance_to(&ahead);
Ok(Expr::Unary(ExprUnary {
attrs: input.call(Attribute::parse_outer)?,
attrs,
op: input.parse()?,
expr: Box::new(unary_expr(input, allow_struct)?),
}))
Expand Down Expand Up @@ -1934,7 +1954,7 @@ pub(crate) mod parsing {
return parse_expr(input, expr, allow_struct, Precedence::Any);
};

if input.peek(Token![.]) || input.peek(Token![?]) {
if input.peek(Token![.]) && !input.peek(Token![..]) || input.peek(Token![?]) {
expr = trailer_helper(input, expr)?;

attrs.extend(expr.replace_attrs(Vec::new()));
Expand Down Expand Up @@ -2428,6 +2448,7 @@ pub(crate) mod parsing {
#[cfg(feature = "full")]
impl Parse for FieldValue {
fn parse(input: ParseStream) -> Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let member: Member = input.parse()?;
let (colon_token, value) = if input.peek(Token![:]) || !member.is_named() {
let colon_token: Token![:] = input.parse()?;
Expand All @@ -2445,7 +2466,7 @@ pub(crate) mod parsing {
};

Ok(FieldValue {
attrs: Vec::new(),
attrs,
member,
colon_token,
expr: value,
Expand All @@ -2462,46 +2483,36 @@ pub(crate) mod parsing {
let content;
let brace_token = braced!(content in input);
let inner_attrs = content.call(Attribute::parse_inner)?;
let attrs = private::attrs(outer_attrs, inner_attrs);

let mut fields = Punctuated::new();
loop {
let attrs = content.call(Attribute::parse_outer)?;
// TODO: optimize using advance_to
if content.fork().parse::<Member>().is_err() {
if attrs.is_empty() {
break;
} else {
return Err(content.error("expected struct field"));
}
while !content.is_empty() {
if content.peek(Token![..]) {
return Ok(ExprStruct {
attrs,
brace_token,
path,
fields,
dot2_token: Some(content.parse()?),
rest: Some(Box::new(content.parse()?)),
});
}

fields.push(FieldValue {
attrs,
..content.parse()?
});

fields.push(content.parse()?);
if !content.peek(Token![,]) {
break;
}
let punct: Token![,] = content.parse()?;
fields.push_punct(punct);
}

let (dot2_token, rest) = if fields.empty_or_trailing() && content.peek(Token![..]) {
let dot2_token: Token![..] = content.parse()?;
let rest: Expr = content.parse()?;
(Some(dot2_token), Some(Box::new(rest)))
} else {
(None, None)
};

Ok(ExprStruct {
attrs: private::attrs(outer_attrs, inner_attrs),
attrs,
brace_token,
path,
fields,
dot2_token,
rest,
dot2_token: None,
rest: None,
})
}

Expand Down
16 changes: 0 additions & 16 deletions src/gen/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,35 +433,27 @@ pub trait Fold {
fn fold_lifetime_def(&mut self, i: LifetimeDef) -> LifetimeDef {
fold_lifetime_def(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit(&mut self, i: Lit) -> Lit {
fold_lit(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit_bool(&mut self, i: LitBool) -> LitBool {
fold_lit_bool(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit_byte(&mut self, i: LitByte) -> LitByte {
fold_lit_byte(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit_byte_str(&mut self, i: LitByteStr) -> LitByteStr {
fold_lit_byte_str(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit_char(&mut self, i: LitChar) -> LitChar {
fold_lit_char(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit_float(&mut self, i: LitFloat) -> LitFloat {
fold_lit_float(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit_int(&mut self, i: LitInt) -> LitInt {
fold_lit_int(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn fold_lit_str(&mut self, i: LitStr) -> LitStr {
fold_lit_str(self, i)
}
Expand Down Expand Up @@ -2189,7 +2181,6 @@ where
bounds: FoldHelper::lift(node.bounds, |it| f.fold_lifetime(it)),
}
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit<F>(f: &mut F, node: Lit) -> Lit
where
F: Fold + ?Sized,
Expand All @@ -2205,7 +2196,6 @@ where
Lit::Verbatim(_binding_0) => Lit::Verbatim(_binding_0),
}
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit_bool<F>(f: &mut F, node: LitBool) -> LitBool
where
F: Fold + ?Sized,
Expand All @@ -2215,7 +2205,6 @@ where
span: f.fold_span(node.span),
}
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit_byte<F>(f: &mut F, node: LitByte) -> LitByte
where
F: Fold + ?Sized,
Expand All @@ -2225,7 +2214,6 @@ where
node.set_span(span);
node
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit_byte_str<F>(f: &mut F, node: LitByteStr) -> LitByteStr
where
F: Fold + ?Sized,
Expand All @@ -2235,7 +2223,6 @@ where
node.set_span(span);
node
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit_char<F>(f: &mut F, node: LitChar) -> LitChar
where
F: Fold + ?Sized,
Expand All @@ -2245,7 +2232,6 @@ where
node.set_span(span);
node
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit_float<F>(f: &mut F, node: LitFloat) -> LitFloat
where
F: Fold + ?Sized,
Expand All @@ -2255,7 +2241,6 @@ where
node.set_span(span);
node
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit_int<F>(f: &mut F, node: LitInt) -> LitInt
where
F: Fold + ?Sized,
Expand All @@ -2265,7 +2250,6 @@ where
node.set_span(span);
node
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn fold_lit_str<F>(f: &mut F, node: LitStr) -> LitStr
where
F: Fold + ?Sized,
Expand Down
17 changes: 0 additions & 17 deletions src/gen/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ macro_rules! full {
unreachable!()
};
}
#[cfg(any(feature = "full", feature = "derive"))]
macro_rules! skip {
($($tt:tt)*) => {};
}
Expand Down Expand Up @@ -434,35 +433,27 @@ pub trait Visit<'ast> {
fn visit_lifetime_def(&mut self, i: &'ast LifetimeDef) {
visit_lifetime_def(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit(&mut self, i: &'ast Lit) {
visit_lit(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_bool(&mut self, i: &'ast LitBool) {
visit_lit_bool(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_byte(&mut self, i: &'ast LitByte) {
visit_lit_byte(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_byte_str(&mut self, i: &'ast LitByteStr) {
visit_lit_byte_str(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_char(&mut self, i: &'ast LitChar) {
visit_lit_char(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_float(&mut self, i: &'ast LitFloat) {
visit_lit_float(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_int(&mut self, i: &'ast LitInt) {
visit_lit_int(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_str(&mut self, i: &'ast LitStr) {
visit_lit_str(self, i)
}
Expand Down Expand Up @@ -2537,7 +2528,6 @@ where
}
}
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit<'ast, V>(v: &mut V, node: &'ast Lit)
where
V: Visit<'ast> + ?Sized,
Expand Down Expand Up @@ -2569,45 +2559,38 @@ where
}
}
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_bool<'ast, V>(v: &mut V, node: &'ast LitBool)
where
V: Visit<'ast> + ?Sized,
{
skip!(node.value);
v.visit_span(&node.span);
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_byte<'ast, V>(v: &mut V, node: &'ast LitByte)
where
V: Visit<'ast> + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_byte_str<'ast, V>(v: &mut V, node: &'ast LitByteStr)
where
V: Visit<'ast> + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_char<'ast, V>(v: &mut V, node: &'ast LitChar)
where
V: Visit<'ast> + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_float<'ast, V>(v: &mut V, node: &'ast LitFloat)
where
V: Visit<'ast> + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_int<'ast, V>(v: &mut V, node: &'ast LitInt)
where
V: Visit<'ast> + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_str<'ast, V>(v: &mut V, node: &'ast LitStr)
where
V: Visit<'ast> + ?Sized,
Expand Down
17 changes: 0 additions & 17 deletions src/gen/visit_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ macro_rules! full {
unreachable!()
};
}
#[cfg(any(feature = "full", feature = "derive"))]
macro_rules! skip {
($($tt:tt)*) => {};
}
Expand Down Expand Up @@ -438,35 +437,27 @@ pub trait VisitMut {
fn visit_lifetime_def_mut(&mut self, i: &mut LifetimeDef) {
visit_lifetime_def_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_mut(&mut self, i: &mut Lit) {
visit_lit_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_bool_mut(&mut self, i: &mut LitBool) {
visit_lit_bool_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_byte_mut(&mut self, i: &mut LitByte) {
visit_lit_byte_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_byte_str_mut(&mut self, i: &mut LitByteStr) {
visit_lit_byte_str_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_char_mut(&mut self, i: &mut LitChar) {
visit_lit_char_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_float_mut(&mut self, i: &mut LitFloat) {
visit_lit_float_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_int_mut(&mut self, i: &mut LitInt) {
visit_lit_int_mut(self, i)
}
#[cfg(any(feature = "derive", feature = "full"))]
fn visit_lit_str_mut(&mut self, i: &mut LitStr) {
visit_lit_str_mut(self, i)
}
Expand Down Expand Up @@ -2543,7 +2534,6 @@ where
}
}
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_mut<V>(v: &mut V, node: &mut Lit)
where
V: VisitMut + ?Sized,
Expand Down Expand Up @@ -2575,45 +2565,38 @@ where
}
}
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_bool_mut<V>(v: &mut V, node: &mut LitBool)
where
V: VisitMut + ?Sized,
{
skip!(node.value);
v.visit_span_mut(&mut node.span);
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_byte_mut<V>(v: &mut V, node: &mut LitByte)
where
V: VisitMut + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_byte_str_mut<V>(v: &mut V, node: &mut LitByteStr)
where
V: VisitMut + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_char_mut<V>(v: &mut V, node: &mut LitChar)
where
V: VisitMut + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_float_mut<V>(v: &mut V, node: &mut LitFloat)
where
V: VisitMut + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_int_mut<V>(v: &mut V, node: &mut LitInt)
where
V: VisitMut + ?Sized,
{
}
#[cfg(any(feature = "derive", feature = "full"))]
pub fn visit_lit_str_mut<V>(v: &mut V, node: &mut LitStr)
where
V: VisitMut + ?Sized,
Expand Down
6 changes: 0 additions & 6 deletions src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ ast_enum_of_structs! {
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
//
// TODO: change syntax-tree-enum link to an intra rustdoc link, currently
// blocked on https://github.com/rust-lang/rust/issues/62833
pub enum GenericParam {
/// A generic type parameter: `T: Into<String>`.
Type(TypeParam),
Expand Down Expand Up @@ -448,9 +445,6 @@ ast_enum_of_structs! {
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
//
// TODO: change syntax-tree-enum link to an intra rustdoc link, currently
// blocked on https://github.com/rust-lang/rust/issues/62833
pub enum WherePredicate {
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
Type(PredicateType),
Expand Down
418 changes: 289 additions & 129 deletions src/item.rs

Large diffs are not rendered by default.

Empty file removed src/keyword.rs
Empty file.
15 changes: 7 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@
//! dynamic library libproc_macro from rustc toolchain.

// Syn types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/syn/1.0.11")]
#![doc(html_root_url = "https://docs.rs/syn/1.0.17")]
#![deny(clippy::all, clippy::pedantic)]
// Ignored clippy lints.
#![allow(
Expand All @@ -265,6 +265,8 @@
clippy::empty_enum,
clippy::if_not_else,
clippy::items_after_statements,
clippy::match_same_arms,
clippy::missing_errors_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::shadow_unrelated,
Expand All @@ -287,7 +289,6 @@ extern crate unicode_xid;
#[cfg(feature = "printing")]
extern crate quote;

#[cfg(any(feature = "full", feature = "derive"))]
#[macro_use]
mod macros;

Expand All @@ -310,7 +311,6 @@ pub use crate::attr::{
AttrStyle, Attribute, AttributeArgs, Meta, MetaList, MetaNameValue, NestedMeta,
};

#[cfg(any(feature = "full", feature = "derive"))]
mod bigint;

#[cfg(any(feature = "full", feature = "derive"))]
Expand Down Expand Up @@ -367,9 +367,7 @@ pub use crate::file::File;
mod lifetime;
pub use crate::lifetime::Lifetime;

#[cfg(any(feature = "full", feature = "derive"))]
mod lit;
#[cfg(any(feature = "full", feature = "derive"))]
pub use crate::lit::{
Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr, StrStyle,
};
Expand Down Expand Up @@ -760,20 +758,21 @@ pub mod export;
mod custom_keyword;
mod custom_punctuation;
mod sealed;
mod span;
mod thread;

#[cfg(feature = "parsing")]
mod lookahead;

#[cfg(feature = "parsing")]
pub mod parse;

mod span;
#[cfg(all(feature = "parsing", feature = "full"))]
mod verbatim;

#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
mod print;

mod thread;

////////////////////////////////////////////////////////////////////////////////

#[allow(dead_code, non_camel_case_types)]
Expand Down
193 changes: 124 additions & 69 deletions src/lit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ use crate::{Error, Result};
ast_enum_of_structs! {
/// A Rust literal such as a string or integer or boolean.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
Expand Down Expand Up @@ -64,9 +61,6 @@ ast_enum_of_structs! {

ast_struct! {
/// A UTF-8 string literal: `"foo"`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub struct LitStr #manual_extra_traits_debug {
repr: Box<LitStrRepr>,
}
Expand All @@ -80,39 +74,27 @@ struct LitStrRepr {

ast_struct! {
/// A byte string literal: `b"foo"`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub struct LitByteStr #manual_extra_traits_debug {
token: Literal,
}
}

ast_struct! {
/// A byte literal: `b'f'`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub struct LitByte #manual_extra_traits_debug {
token: Literal,
}
}

ast_struct! {
/// A character literal: `'a'`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub struct LitChar #manual_extra_traits_debug {
token: Literal,
}
}

ast_struct! {
/// An integer literal: `1` or `1u16`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub struct LitInt #manual_extra_traits_debug {
repr: Box<LitIntRepr>,
}
Expand All @@ -129,9 +111,6 @@ ast_struct! {
/// A floating point literal: `1f64` or `1.0e10f64`.
///
/// Must be finite. May not be infinte or NaN.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub struct LitFloat #manual_extra_traits_debug {
repr: Box<LitFloatRepr>,
}
Expand All @@ -146,9 +125,6 @@ struct LitFloatRepr {

ast_struct! {
/// A boolean literal: `true` or `false`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub struct LitBool #manual_extra_traits_debug {
pub value: bool,
pub span: Span,
Expand Down Expand Up @@ -403,18 +379,23 @@ impl LitChar {

impl LitInt {
pub fn new(repr: &str, span: Span) -> Self {
if let Some((digits, suffix)) = value::parse_lit_int(repr) {
let mut token = value::to_literal(repr);
token.set_span(span);
LitInt {
repr: Box::new(LitIntRepr {
token,
digits,
suffix,
}),
}
} else {
panic!("Not an integer literal: `{}`", repr);
let (digits, suffix) = match value::parse_lit_int(repr) {
Some(parse) => parse,
None => panic!("Not an integer literal: `{}`", repr),
};

let mut token = match value::to_literal(repr, &digits, &suffix) {
Some(token) => token,
None => panic!("Unsupported integer literal: `{}`", repr),
};

token.set_span(span);
LitInt {
repr: Box::new(LitIntRepr {
token,
digits,
suffix,
}),
}
}

Expand Down Expand Up @@ -492,18 +473,23 @@ impl Display for LitInt {

impl LitFloat {
pub fn new(repr: &str, span: Span) -> Self {
if let Some((digits, suffix)) = value::parse_lit_float(repr) {
let mut token = value::to_literal(repr);
token.set_span(span);
LitFloat {
repr: Box::new(LitFloatRepr {
token,
digits,
suffix,
}),
}
} else {
panic!("Not a float literal: `{}`", repr);
let (digits, suffix) = match value::parse_lit_float(repr) {
Some(parse) => parse,
None => panic!("Not a float literal: `{}`", repr),
};

let mut token = match value::to_literal(repr, &digits, &suffix) {
Some(token) => token,
None => panic!("Unsupported float literal: `{}`", repr),
};

token.set_span(span);
LitFloat {
repr: Box::new(LitFloatRepr {
token,
digits,
suffix,
}),
}
}

Expand Down Expand Up @@ -668,9 +654,6 @@ lit_extra_traits!(LitBool, value);
ast_enum! {
/// The style of a string literal, either plain quoted or a raw string like
/// `r##"data"##`.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
pub enum StrStyle #no_visit {
/// An ordinary string like `"data"`.
Cooked,
Expand All @@ -691,33 +674,83 @@ pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use crate::buffer::Cursor;
use crate::parse::{Parse, ParseStream, Result};
use proc_macro2::Punct;

impl Parse for Lit {
fn parse(input: ParseStream) -> Result<Self> {
input.step(|cursor| {
if let Some((lit, rest)) = cursor.literal() {
return Ok((Lit::new(lit), rest));
}
while let Some((ident, rest)) = cursor.ident() {
let value = if ident == "true" {
true
} else if ident == "false" {
false
} else {
break;
};
let lit_bool = LitBool {
value,
span: ident.span(),
};
return Ok((Lit::Bool(lit_bool), rest));

if let Some((ident, rest)) = cursor.ident() {
let value = ident == "true";
if value || ident == "false" {
let lit_bool = LitBool {
value,
span: ident.span(),
};
return Ok((Lit::Bool(lit_bool), rest));
}
}

if let Some((punct, rest)) = cursor.punct() {
if punct.as_char() == '-' {
if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
return Ok((lit, rest));
}
}
}

Err(cursor.error("expected literal"))
})
}
}

fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
let (lit, rest) = cursor.literal()?;

let mut span = neg.span();
span = span.join(lit.span()).unwrap_or(span);

let mut repr = lit.to_string();
repr.insert(0, '-');

if !(repr.ends_with("f32") || repr.ends_with("f64")) {
if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
if let Some(mut token) = value::to_literal(&repr, &digits, &suffix) {
token.set_span(span);
return Some((
Lit::Int(LitInt {
repr: Box::new(LitIntRepr {
token,
digits,
suffix,
}),
}),
rest,
));
}
}
}

let (digits, suffix) = value::parse_lit_float(&repr)?;
let mut token = value::to_literal(&repr, &digits, &suffix)?;
token.set_span(span);
Some((
Lit::Float(LitFloat {
repr: Box::new(LitFloatRepr {
token,
digits,
suffix,
}),
}),
rest,
))
}

impl Parse for LitStr {
fn parse(input: ParseStream) -> Result<Self> {
let head = input.fork();
Expand Down Expand Up @@ -1372,11 +1405,33 @@ mod value {
}
}

pub fn to_literal(s: &str) -> Literal {
let stream = s.parse::<TokenStream>().unwrap();
match stream.into_iter().next().unwrap() {
TokenTree::Literal(l) => l,
_ => unreachable!(),
pub fn to_literal(repr: &str, digits: &str, suffix: &str) -> Option<Literal> {
if repr.starts_with('-') {
if suffix == "f64" {
digits.parse().ok().map(Literal::f64_suffixed)
} else if suffix == "f32" {
digits.parse().ok().map(Literal::f32_suffixed)
} else if suffix == "i64" {
digits.parse().ok().map(Literal::i64_suffixed)
} else if suffix == "i32" {
digits.parse().ok().map(Literal::i32_suffixed)
} else if suffix == "i16" {
digits.parse().ok().map(Literal::i16_suffixed)
} else if suffix == "i8" {
digits.parse().ok().map(Literal::i8_suffixed)
} else if !suffix.is_empty() {
None
} else if digits.contains('.') {
digits.parse().ok().map(Literal::f64_unsuffixed)
} else {
digits.parse().ok().map(Literal::i64_unsuffixed)
}
} else {
let stream = repr.parse::<TokenStream>().unwrap();
match stream.into_iter().next().unwrap() {
TokenTree::Literal(l) => Some(l),
_ => unreachable!(),
}
}
}
}
43 changes: 25 additions & 18 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,20 +374,6 @@ pub(crate) fn advance_step_cursor<'c, 'a>(proof: StepCursor<'c, 'a>, to: Cursor<
unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(to) }
}

fn skip(input: ParseStream) -> bool {
input
.step(|cursor| {
if let Some((_lifetime, rest)) = cursor.lifetime() {
Ok((true, rest))
} else if let Some((_token, rest)) = cursor.token_tree() {
Ok((true, rest))
} else {
Ok((false, *cursor))
}
})
.unwrap()
}

pub(crate) fn new_parse_buffer(
scope: Span,
cursor: Cursor,
Expand Down Expand Up @@ -598,14 +584,17 @@ impl<'a> ParseBuffer<'a> {
/// }
/// ```
pub fn peek2<T: Peek>(&self, token: T) -> bool {
let ahead = self.fork();
skip(&ahead) && ahead.peek(token)
let _ = token;
self.cursor().skip().map_or(false, T::Token::peek)
}

/// Looks at the third-next token in the parse stream.
pub fn peek3<T: Peek>(&self, token: T) -> bool {
let ahead = self.fork();
skip(&ahead) && skip(&ahead) && ahead.peek(token)
let _ = token;
self.cursor()
.skip()
.and_then(Cursor::skip)
.map_or(false, T::Token::peek)
}

/// Parses zero or more occurrences of `T` separated by punctuation of type
Expand Down Expand Up @@ -989,6 +978,18 @@ impl<'a> ParseBuffer<'a> {
Ok(node)
}

/// Returns the `Span` of the next token in the parse stream, or
/// `Span::call_site()` if this parse stream has completely exhausted its
/// input `TokenStream`.
pub fn span(&self) -> Span {
let cursor = self.cursor();
if cursor.eof() {
self.scope
} else {
crate::buffer::open_span_of_group(cursor)
}
}

/// Provides low-level access to the token representation underlying this
/// parse stream.
///
Expand Down Expand Up @@ -1116,13 +1117,15 @@ pub trait Parser: Sized {

// Not public API.
#[doc(hidden)]
#[cfg(any(feature = "full", feature = "derive"))]
fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
let _ = scope;
self.parse2(tokens)
}

// Not public API.
#[doc(hidden)]
#[cfg(any(feature = "full", feature = "derive"))]
fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> {
input.parse().and_then(|tokens| self.parse2(tokens))
}
Expand Down Expand Up @@ -1154,6 +1157,7 @@ where
}

#[doc(hidden)]
#[cfg(any(feature = "full", feature = "derive"))]
fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
let buf = TokenBuffer::new2(tokens);
let cursor = buf.begin();
Expand All @@ -1169,15 +1173,18 @@ where
}

#[doc(hidden)]
#[cfg(any(feature = "full", feature = "derive"))]
fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> {
self(input)
}
}

#[cfg(any(feature = "full", feature = "derive"))]
pub(crate) fn parse_scoped<F: Parser>(f: F, scope: Span, tokens: TokenStream) -> Result<F::Output> {
f.__parse_scoped(scope, tokens)
}

#[cfg(any(feature = "full", feature = "derive"))]
pub(crate) fn parse_stream<F: Parser>(f: F, input: ParseStream) -> Result<F::Output> {
f.__parse_stream(input)
}
Expand Down
11 changes: 11 additions & 0 deletions src/parse_quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@
/// or inner like `#![...]`
/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
/// `P` with optional trailing punctuation
/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
///
/// [`Punctuated<T, P>`]: punctuated::Punctuated
/// [`Vec<Stmt>`]: Block::parse_within
///
/// # Panics
///
Expand Down Expand Up @@ -112,6 +114,8 @@ impl<T: Parse> ParseQuote for T {
use crate::punctuated::Punctuated;
#[cfg(any(feature = "full", feature = "derive"))]
use crate::{attr, Attribute};
#[cfg(feature = "full")]
use crate::{Block, Stmt};

#[cfg(any(feature = "full", feature = "derive"))]
impl ParseQuote for Attribute {
Expand All @@ -129,3 +133,10 @@ impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
Self::parse_terminated(input)
}
}

#[cfg(feature = "full")]
impl ParseQuote for Vec<Stmt> {
fn parse(input: ParseStream) -> Result<Self> {
Block::parse_within(input)
}
}
101 changes: 70 additions & 31 deletions src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,11 +386,12 @@ mod parsing {
use super::*;

use crate::ext::IdentExt;
use crate::parse::{Parse, ParseStream, Result};
use crate::parse::{Parse, ParseBuffer, ParseStream, Result};
use crate::path;

impl Parse for Pat {
fn parse(input: ParseStream) -> Result<Self> {
let begin = input.fork();
let lookahead = input.lookahead1();
if lookahead.peek(Ident)
&& ({
Expand Down Expand Up @@ -434,18 +435,19 @@ mod parsing {
} else if lookahead.peek(token::Bracket) {
input.call(pat_slice).map(Pat::Slice)
} else if lookahead.peek(Token![..]) && !input.peek(Token![...]) {
input.call(pat_rest).map(Pat::Rest)
pat_range_half_open(input, begin)
} else {
Err(lookahead.error())
}
}
}

fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
let begin = input.fork();
let (qself, path) = path::parsing::qpath(input, true)?;

if input.peek(Token![..]) {
return pat_range(input, qself, path).map(Pat::Range);
return pat_range(input, begin, qself, path);
}

if qself.is_some() {
Expand Down Expand Up @@ -487,7 +489,7 @@ mod parsing {
} else if input.peek(token::Paren) {
pat_tuple_struct(input, path).map(Pat::TupleStruct)
} else if input.peek(Token![..]) {
pat_range(input, qself, path).map(Pat::Range)
pat_range(input, begin, qself, path)
} else {
Ok(Pat::Path(PatPath {
attrs: Vec::new(),
Expand Down Expand Up @@ -624,17 +626,44 @@ mod parsing {
})
}

fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatRange> {
Ok(PatRange {
attrs: Vec::new(),
lo: Box::new(Expr::Path(ExprPath {
fn pat_range(
input: ParseStream,
begin: ParseBuffer,
qself: Option<QSelf>,
path: Path,
) -> Result<Pat> {
let limits: RangeLimits = input.parse()?;
let hi = input.call(pat_lit_expr)?;
if let Some(hi) = hi {
Ok(Pat::Range(PatRange {
attrs: Vec::new(),
qself,
path,
})),
limits: input.parse()?,
hi: input.call(pat_lit_expr)?,
})
lo: Box::new(Expr::Path(ExprPath {
attrs: Vec::new(),
qself,
path,
})),
limits,
hi,
}))
} else {
Ok(Pat::Verbatim(verbatim::between(begin, input)))
}
}

fn pat_range_half_open(input: ParseStream, begin: ParseBuffer) -> Result<Pat> {
let limits: RangeLimits = input.parse()?;
let hi = input.call(pat_lit_expr)?;
if hi.is_some() {
Ok(Pat::Verbatim(verbatim::between(begin, input)))
} else {
match limits {
RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest {
attrs: Vec::new(),
dot2_token,
})),
RangeLimits::Closed(_) => Err(input.error("expected range upper bound")),
}
}
}

fn pat_tuple(input: ParseStream) -> Result<PatTuple> {
Expand Down Expand Up @@ -669,14 +698,21 @@ mod parsing {
}

fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
let lo = input.call(pat_lit_expr)?;
let begin = input.fork();
let lo = input.call(pat_lit_expr)?.unwrap();
if input.peek(Token![..]) {
Ok(Pat::Range(PatRange {
attrs: Vec::new(),
lo,
limits: input.parse()?,
hi: input.call(pat_lit_expr)?,
}))
let limits: RangeLimits = input.parse()?;
let hi = input.call(pat_lit_expr)?;
if let Some(hi) = hi {
Ok(Pat::Range(PatRange {
attrs: Vec::new(),
lo,
limits,
hi,
}))
} else {
Ok(Pat::Verbatim(verbatim::between(begin, input)))
}
} else {
Ok(Pat::Lit(PatLit {
attrs: Vec::new(),
Expand All @@ -685,7 +721,17 @@ mod parsing {
}
}

fn pat_lit_expr(input: ParseStream) -> Result<Box<Expr>> {
fn pat_lit_expr(input: ParseStream) -> Result<Option<Box<Expr>>> {
if input.is_empty()
|| input.peek(Token![|])
|| input.peek(Token![=>])
|| input.peek(Token![:]) && !input.peek(Token![::])
|| input.peek(Token![,])
|| input.peek(Token![;])
{
return Ok(None);
}

let neg: Option<Token![-]> = input.parse()?;

let lookahead = input.lookahead1();
Expand All @@ -705,15 +751,15 @@ mod parsing {
return Err(lookahead.error());
};

Ok(Box::new(if let Some(neg) = neg {
Ok(Some(Box::new(if let Some(neg) = neg {
Expr::Unary(ExprUnary {
attrs: Vec::new(),
op: UnOp::Neg(neg),
expr: Box::new(expr),
})
} else {
expr
}))
})))
}

fn pat_slice(input: ParseStream) -> Result<PatSlice> {
Expand All @@ -737,13 +783,6 @@ mod parsing {
elems,
})
}

fn pat_rest(input: ParseStream) -> Result<PatRest> {
Ok(PatRest {
attrs: Vec::new(),
dot2_token: input.parse()?,
})
}
}

#[cfg(feature = "printing")]
Expand Down
17 changes: 7 additions & 10 deletions src/punctuated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,19 @@ impl<T, P> Punctuated<T, P> {
self.iter().next()
}

/// Mutably borrows the first element in this sequence.
pub fn first_mut(&mut self) -> Option<&mut T> {
self.iter_mut().next()
}

/// Borrows the last element in this sequence.
pub fn last(&self) -> Option<&T> {
if self.last.is_some() {
self.last.as_ref().map(Box::as_ref)
} else {
self.inner.last().map(|pair| &pair.0)
}
self.iter().next_back()
}

/// Mutably borrows the last element in this sequence.
pub fn last_mut(&mut self) -> Option<&mut T> {
if self.last.is_some() {
self.last.as_mut().map(Box::as_mut)
} else {
self.inner.last_mut().map(|pair| &mut pair.0)
}
self.iter_mut().next_back()
}

/// Returns an iterator over borrowed syntax tree nodes of type `&T`.
Expand Down
101 changes: 53 additions & 48 deletions src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ ast_struct! {
pub mod parsing {
use super::*;

use crate::parse::discouraged::Speculative;
use crate::parse::{Parse, ParseStream, Result};
use crate::punctuated::Punctuated;
use proc_macro2::TokenStream;

impl Block {
/// Parse the body of a block as zero or more statements, possibly
Expand Down Expand Up @@ -106,8 +108,8 @@ pub mod parsing {
pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
let mut stmts = Vec::new();
loop {
while input.peek(Token![;]) {
input.parse::<Token![;]>()?;
while let Some(semi) = input.parse::<Option<Token![;]>>()? {
stmts.push(Stmt::Semi(Expr::Verbatim(TokenStream::new()), semi));
}
if input.is_empty() {
break;
Expand Down Expand Up @@ -146,55 +148,55 @@ pub mod parsing {
}

fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
// TODO: optimize using advance_to
let mut attrs = input.call(Attribute::parse_outer)?;

// brace-style macros; paren and bracket macros get parsed as
// expression statements.
let ahead = input.fork();
ahead.call(Attribute::parse_outer)?;
if let Ok(path) = ahead.call(Path::parse_mod_style) {
if ahead.peek(Token![!]) && (ahead.peek2(token::Brace) || ahead.peek2(Ident)) {
input.advance_to(&ahead);
return stmt_mac(input, attrs, path);
}
}

if {
let ahead = ahead.fork();
// Only parse braces here; paren and bracket will get parsed as
// expression statements
ahead.call(Path::parse_mod_style).is_ok()
&& ahead.parse::<Token![!]>().is_ok()
&& (ahead.peek(token::Brace) || ahead.peek(Ident))
} {
stmt_mac(input)
} else if ahead.peek(Token![let]) {
stmt_local(input).map(Stmt::Local)
} else if ahead.peek(Token![pub])
|| ahead.peek(Token![crate]) && !ahead.peek2(Token![::])
|| ahead.peek(Token![extern]) && !ahead.peek2(Token![::])
|| ahead.peek(Token![use])
|| ahead.peek(Token![static]) && (ahead.peek2(Token![mut]) || ahead.peek2(Ident))
|| ahead.peek(Token![const])
|| ahead.peek(Token![unsafe]) && !ahead.peek2(token::Brace)
|| ahead.peek(Token![async])
&& (ahead.peek2(Token![unsafe])
|| ahead.peek2(Token![extern])
|| ahead.peek2(Token![fn]))
|| ahead.peek(Token![fn])
|| ahead.peek(Token![mod])
|| ahead.peek(Token![type])
|| ahead.peek(item::parsing::existential) && ahead.peek2(Token![type])
|| ahead.peek(Token![struct])
|| ahead.peek(Token![enum])
|| ahead.peek(Token![union]) && ahead.peek2(Ident)
|| ahead.peek(Token![auto]) && ahead.peek2(Token![trait])
|| ahead.peek(Token![trait])
|| ahead.peek(Token![default])
&& (ahead.peek2(Token![unsafe]) || ahead.peek2(Token![impl]))
|| ahead.peek(Token![impl])
|| ahead.peek(Token![macro])
if input.peek(Token![let]) {
stmt_local(input, attrs).map(Stmt::Local)
} else if input.peek(Token![pub])
|| input.peek(Token![crate]) && !input.peek2(Token![::])
|| input.peek(Token![extern]) && !input.peek2(Token![::])
|| input.peek(Token![use])
|| input.peek(Token![static]) && (input.peek2(Token![mut]) || input.peek2(Ident))
|| input.peek(Token![const])
|| input.peek(Token![unsafe]) && !input.peek2(token::Brace)
|| input.peek(Token![async])
&& (input.peek2(Token![unsafe])
|| input.peek2(Token![extern])
|| input.peek2(Token![fn]))
|| input.peek(Token![fn])
|| input.peek(Token![mod])
|| input.peek(Token![type])
|| input.peek(item::parsing::existential) && input.peek2(Token![type])
|| input.peek(Token![struct])
|| input.peek(Token![enum])
|| input.peek(Token![union]) && input.peek2(Ident)
|| input.peek(Token![auto]) && input.peek2(Token![trait])
|| input.peek(Token![trait])
|| input.peek(Token![default])
&& (input.peek2(Token![unsafe]) || input.peek2(Token![impl]))
|| input.peek(Token![impl])
|| input.peek(Token![macro])
{
input.parse().map(Stmt::Item)
let mut item: Item = input.parse()?;
attrs.extend(item.replace_attrs(Vec::new()));
item.replace_attrs(attrs);
Ok(Stmt::Item(item))
} else {
stmt_expr(input, allow_nosemi)
stmt_expr(input, allow_nosemi, attrs)
}
}

fn stmt_mac(input: ParseStream) -> Result<Stmt> {
let attrs = input.call(Attribute::parse_outer)?;
let path = input.call(Path::parse_mod_style)?;
fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> {
let bang_token: Token![!] = input.parse()?;
let ident: Option<Ident> = input.parse()?;
let (delimiter, tokens) = mac::parse_delimiter(input)?;
Expand All @@ -213,9 +215,9 @@ pub mod parsing {
})))
}

fn stmt_local(input: ParseStream) -> Result<Local> {
fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> {
Ok(Local {
attrs: input.call(Attribute::parse_outer)?,
attrs,
let_token: input.parse()?,
pat: {
let leading_vert: Option<Token![|]> = input.parse()?;
Expand Down Expand Up @@ -265,8 +267,11 @@ pub mod parsing {
})
}

fn stmt_expr(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
let mut attrs = input.call(Attribute::parse_outer)?;
fn stmt_expr(
input: ParseStream,
allow_nosemi: bool,
mut attrs: Vec<Attribute>,
) -> Result<Stmt> {
let mut e = expr::parsing::expr_early(input)?;

attrs.extend(e.replace_attrs(Vec::new()));
Expand Down
3 changes: 1 addition & 2 deletions src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@
//! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html
//! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html

use std;
#[cfg(feature = "extra-traits")]
use std::cmp;
#[cfg(feature = "extra-traits")]
Expand Down Expand Up @@ -856,7 +855,7 @@ pub mod parsing {
}

pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
let mut spans = [input.cursor().span(); 3];
let mut spans = [input.span(); 3];
punct_helper(input, token, &mut spans)?;
Ok(S::from_spans(&spans))
}
Expand Down
15 changes: 15 additions & 0 deletions src/verbatim.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::parse::{ParseBuffer, ParseStream};
use proc_macro2::TokenStream;
use std::iter;

pub fn between<'a>(begin: ParseBuffer<'a>, end: ParseStream<'a>) -> TokenStream {
let end = end.cursor();
let mut cursor = begin.cursor();
let mut tokens = TokenStream::new();
while cursor != end {
let (tt, next) = cursor.token_tree().unwrap();
tokens.extend(iter::once(tt));
cursor = next;
}
tokens
}
42 changes: 9 additions & 33 deletions syn.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.0.11",
"version": "1.0.17",
"types": [
{
"ident": "Abi",
Expand Down Expand Up @@ -3307,10 +3307,7 @@
{
"ident": "Lit",
"features": {
"any": [
"derive",
"full"
]
"any": []
},
"variants": {
"Str": [
Expand Down Expand Up @@ -3358,10 +3355,7 @@
{
"ident": "LitBool",
"features": {
"any": [
"derive",
"full"
]
"any": []
},
"fields": {
"value": {
Expand All @@ -3375,55 +3369,37 @@
{
"ident": "LitByte",
"features": {
"any": [
"derive",
"full"
]
"any": []
}
},
{
"ident": "LitByteStr",
"features": {
"any": [
"derive",
"full"
]
"any": []
}
},
{
"ident": "LitChar",
"features": {
"any": [
"derive",
"full"
]
"any": []
}
},
{
"ident": "LitFloat",
"features": {
"any": [
"derive",
"full"
]
"any": []
}
},
{
"ident": "LitInt",
"features": {
"any": [
"derive",
"full"
]
"any": []
}
},
{
"ident": "LitStr",
"features": {
"any": [
"derive",
"full"
]
"any": []
}
},
{
Expand Down
114 changes: 55 additions & 59 deletions tests/common/eq.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;
extern crate rustc_target;
extern crate syntax;
extern crate syntax_pos;

use std::mem;

use rustc_ast::ast::{
AngleBracketedArgs, AnonConst, Arm, AsmDialect, AssocItemKind, AssocTyConstraint,
AssocTyConstraintKind, Async, AttrId, AttrItem, AttrKind, AttrStyle, Attribute, BareFnTy,
BinOpKind, BindingMode, Block, BlockCheckMode, BorrowKind, CaptureBy, Const, Crate, CrateSugar,
Defaultness, EnumDef, Expr, ExprKind, Extern, Field, FieldPat, FloatTy, FnDecl, FnHeader,
FnRetTy, FnSig, ForeignItemKind, ForeignMod, GenericArg, GenericArgs, GenericBound,
GenericParam, GenericParamKind, Generics, GlobalAsm, Ident, ImplPolarity, InlineAsm,
InlineAsmOutput, IntTy, IsAuto, Item, ItemKind, Label, Lifetime, Lit, LitFloatType, LitIntType,
LitKind, Local, MacArgs, MacCall, MacDelimiter, MacStmtStyle, MacroDef, Mod, Movability, MutTy,
Mutability, NodeId, Param, ParenthesizedArgs, Pat, PatKind, Path, PathSegment, PolyTraitRef,
QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, StrLit, StrStyle, StructField,
TraitBoundModifier, TraitObjectSyntax, TraitRef, Ty, TyKind, UintTy, UnOp, Unsafe,
UnsafeSource, UseTree, UseTreeKind, Variant, VariantData, VisibilityKind, WhereBoundPredicate,
WhereClause, WhereEqPredicate, WherePredicate, WhereRegionPredicate,
};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, DelimToken, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::util::comments;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::thin_vec::ThinVec;
use syntax::ast::{
AngleBracketedArgs, AnonConst, Arm, AsmDialect, AssocTyConstraint, AssocTyConstraintKind,
AttrId, AttrItem, AttrKind, AttrStyle, Attribute, BareFnTy, BinOpKind, BindingMode, Block,
BlockCheckMode, BorrowKind, CaptureBy, Constness, Crate, CrateSugar, Defaultness, EnumDef,
Expr, ExprKind, Extern, Field, FieldPat, FloatTy, FnDecl, FnHeader, FnSig, ForeignItem,
ForeignItemKind, ForeignMod, FunctionRetTy, GenericArg, GenericArgs, GenericBound,
GenericParam, GenericParamKind, Generics, GlobalAsm, Ident, ImplItem, ImplItemKind,
ImplPolarity, InlineAsm, InlineAsmOutput, IntTy, IsAsync, IsAuto, Item, ItemKind, Label,
Lifetime, Lit, LitFloatType, LitIntType, LitKind, Local, Mac, MacDelimiter, MacStmtStyle,
MacroDef, Mod, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs, Pat, PatKind,
Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind,
StrLit, StrStyle, StructField, TraitBoundModifier, TraitItem, TraitItemKind, TraitObjectSyntax,
TraitRef, Ty, TyKind, UintTy, UnOp, UnsafeSource, Unsafety, UseTree, UseTreeKind, Variant,
VariantData, VisibilityKind, WhereBoundPredicate, WhereClause, WhereEqPredicate,
WherePredicate, WhereRegionPredicate,
};
use syntax::ptr::P;
use syntax::source_map::Spanned;
use syntax::symbol::{sym, Symbol};
use syntax::token::{self, DelimToken, Token, TokenKind};
use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
use syntax::util::comments;
use syntax_pos::{Span, SyntaxContext, DUMMY_SP};
use rustc_span::source_map::Spanned;
use rustc_span::{sym, Span, Symbol, SyntaxContext, DUMMY_SP};

pub trait SpanlessEq {
fn eq(&self, other: &Self) -> bool;
Expand Down Expand Up @@ -130,11 +128,11 @@ spanless_eq_partial_eq!(DelimToken);

macro_rules! spanless_eq_struct {
{
$name:ident;
$name:ident $(<$param:ident>)?;
$([$field:ident $other:ident])*
$(![$ignore:ident])*
} => {
impl SpanlessEq for $name {
impl $(<$param: SpanlessEq>)* SpanlessEq for $name $(<$param>)* {
fn eq(&self, other: &Self) -> bool {
let $name { $($field,)* $($ignore: _,)* } = self;
let $name { $($field: $other,)* $($ignore: _,)* } = other;
Expand All @@ -144,14 +142,14 @@ macro_rules! spanless_eq_struct {
};

{
$name:ident;
$name:ident $(<$param:ident>)?;
$([$field:ident $other:ident])*
$next:ident
$($rest:ident)*
$(!$ignore:ident)*
} => {
spanless_eq_struct! {
$name;
$name $(<$param>)*;
$([$field $other])*
[$next other]
$($rest)*
Expand All @@ -160,14 +158,14 @@ macro_rules! spanless_eq_struct {
};

{
$name:ident;
$name:ident $(<$param:ident>)?;
$([$field:ident $other:ident])*
$(![$ignore:ident])*
!$next:ident
$(!$rest:ident)*
} => {
spanless_eq_struct! {
$name;
$name $(<$param>)*;
$([$field $other])*
$(![$ignore])*
![$next]
Expand Down Expand Up @@ -265,33 +263,31 @@ spanless_eq_struct!(AngleBracketedArgs; span args constraints);
spanless_eq_struct!(AnonConst; id value);
spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder);
spanless_eq_struct!(AssocTyConstraint; id ident kind span);
spanless_eq_struct!(AttrItem; path tokens);
spanless_eq_struct!(AttrItem; path args);
spanless_eq_struct!(Attribute; kind id style span);
spanless_eq_struct!(BareFnTy; unsafety ext generic_params decl);
spanless_eq_struct!(Block; stmts id rules span);
spanless_eq_struct!(Crate; module attrs span);
spanless_eq_struct!(Crate; module attrs span proc_macros);
spanless_eq_struct!(EnumDef; variants);
spanless_eq_struct!(Expr; id kind span attrs);
spanless_eq_struct!(Field; attrs id span ident expr is_shorthand is_placeholder);
spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs id span is_placeholder);
spanless_eq_struct!(FnDecl; inputs output);
spanless_eq_struct!(FnHeader; constness asyncness unsafety ext);
spanless_eq_struct!(FnSig; header decl);
spanless_eq_struct!(ForeignItem; attrs id span vis ident kind);
spanless_eq_struct!(ForeignMod; abi items);
spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind);
spanless_eq_struct!(Generics; params where_clause span);
spanless_eq_struct!(GlobalAsm; asm);
spanless_eq_struct!(ImplItem; attrs id span vis ident defaultness generics kind !tokens);
spanless_eq_struct!(InlineAsm; asm asm_str_style outputs inputs clobbers volatile alignstack dialect);
spanless_eq_struct!(InlineAsmOutput; constraint expr is_rw is_indirect);
spanless_eq_struct!(Item; attrs id span vis ident kind !tokens);
spanless_eq_struct!(Item<K>; attrs id span vis ident kind !tokens);
spanless_eq_struct!(Label; ident);
spanless_eq_struct!(Lifetime; id ident);
spanless_eq_struct!(Lit; token kind span);
spanless_eq_struct!(Local; pat ty init id span attrs);
spanless_eq_struct!(Mac; path delim tts span prior_type_ascription);
spanless_eq_struct!(MacroDef; tokens legacy);
spanless_eq_struct!(MacCall; path args prior_type_ascription);
spanless_eq_struct!(MacroDef; body macro_rules);
spanless_eq_struct!(Mod; inner items inline);
spanless_eq_struct!(MutTy; ty mutbl);
spanless_eq_struct!(Param; attrs ty pat id span is_placeholder);
Expand All @@ -305,7 +301,6 @@ spanless_eq_struct!(Stmt; id kind span);
spanless_eq_struct!(StrLit; style symbol suffix span symbol_unescaped);
spanless_eq_struct!(StructField; attrs id span vis ident ty is_placeholder);
spanless_eq_struct!(Token; kind span);
spanless_eq_struct!(TraitItem; attrs id span vis ident generics kind !tokens);
spanless_eq_struct!(TraitRef; path ref_id);
spanless_eq_struct!(Ty; id kind span);
spanless_eq_struct!(UseTree; prefix kind span);
Expand All @@ -315,71 +310,72 @@ spanless_eq_struct!(WhereClause; predicates span);
spanless_eq_struct!(WhereEqPredicate; id span lhs_ty rhs_ty);
spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds);
spanless_eq_enum!(AsmDialect; Att Intel);
spanless_eq_enum!(AssocItemKind; Const(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) MacCall(0));
spanless_eq_enum!(AssocTyConstraintKind; Equality(ty) Bound(bounds));
spanless_eq_enum!(Async; Yes(span closure_id return_impl_trait_id) No);
spanless_eq_enum!(AttrKind; Normal(0) DocComment(0));
spanless_eq_enum!(AttrStyle; Outer Inner);
spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt);
spanless_eq_enum!(BindingMode; ByRef(0) ByValue(0));
spanless_eq_enum!(BlockCheckMode; Default Unsafe(0));
spanless_eq_enum!(BorrowKind; Ref Raw);
spanless_eq_enum!(CaptureBy; Value Ref);
spanless_eq_enum!(Constness; Const NotConst);
spanless_eq_enum!(Const; Yes(0) No);
spanless_eq_enum!(CrateSugar; PubCrate JustCrate);
spanless_eq_enum!(Defaultness; Default Final);
spanless_eq_enum!(Defaultness; Default(0) Final);
spanless_eq_enum!(Extern; None Implicit Explicit(0));
spanless_eq_enum!(FloatTy; F32 F64);
spanless_eq_enum!(ForeignItemKind; Fn(0 1) Static(0 1) Ty Macro(0));
spanless_eq_enum!(FunctionRetTy; Default(0) Ty(0));
spanless_eq_enum!(FnRetTy; Default(0) Ty(0));
spanless_eq_enum!(ForeignItemKind; Static(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) MacCall(0));
spanless_eq_enum!(GenericArg; Lifetime(0) Type(0) Const(0));
spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0));
spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0));
spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty));
spanless_eq_enum!(ImplItemKind; Const(0 1) Method(0 1) TyAlias(0) Macro(0));
spanless_eq_enum!(ImplPolarity; Positive Negative);
spanless_eq_enum!(ImplPolarity; Positive Negative(0));
spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128);
spanless_eq_enum!(IsAsync; Async(closure_id return_impl_trait_id) NotAsync);
spanless_eq_enum!(IsAuto; Yes No);
spanless_eq_enum!(LitFloatType; Suffixed(0) Unsuffixed);
spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed);
spanless_eq_enum!(MacArgs; Empty Delimited(0 1 2) Eq(0 1));
spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace);
spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces);
spanless_eq_enum!(Movability; Static Movable);
spanless_eq_enum!(Mutability; Mutable Immutable);
spanless_eq_enum!(Mutability; Mut Not);
spanless_eq_enum!(RangeEnd; Included(0) Excluded);
spanless_eq_enum!(RangeLimits; HalfOpen Closed);
spanless_eq_enum!(StmtKind; Local(0) Item(0) Expr(0) Semi(0) Mac(0));
spanless_eq_enum!(StmtKind; Local(0) Item(0) Expr(0) Semi(0) Empty MacCall(0));
spanless_eq_enum!(StrStyle; Cooked Raw(0));
spanless_eq_enum!(TokenTree; Token(0) Delimited(0 1 2));
spanless_eq_enum!(TraitBoundModifier; None Maybe);
spanless_eq_enum!(TraitItemKind; Const(0 1) Method(0 1) Type(0 1) Macro(0));
spanless_eq_enum!(TraitBoundModifier; None Maybe MaybeConst MaybeConstMaybe);
spanless_eq_enum!(TraitObjectSyntax; Dyn None);
spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128);
spanless_eq_enum!(UnOp; Deref Not Neg);
spanless_eq_enum!(Unsafe; Yes(0) No);
spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided);
spanless_eq_enum!(Unsafety; Unsafe Normal);
spanless_eq_enum!(UseTreeKind; Simple(0 1 2) Nested(0) Glob);
spanless_eq_enum!(VariantData; Struct(0 1) Tuple(0 1) Unit(0));
spanless_eq_enum!(VisibilityKind; Public Crate(0) Restricted(path id) Inherited);
spanless_eq_enum!(WherePredicate; BoundPredicate(0) RegionPredicate(0) EqPredicate(0));
spanless_eq_enum!(ExprKind; Box(0) Array(0) Call(0 1) MethodCall(0 1) Tup(0)
Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1) Let(0 1) If(0 1 2)
While(0 1 2) ForLoop(0 1 2 3) Loop(0 1) Match(0 1) Closure(0 1 2 3 4 5)
Block(0 1) Async(0 1 2) Await(0) TryBlock(0) Assign(0 1) AssignOp(0 1 2)
Block(0 1) Async(0 1 2) Await(0) TryBlock(0) Assign(0 1 2) AssignOp(0 1 2)
Field(0 1) Index(0 1) Range(0 1 2) Path(0 1) AddrOf(0 1 2) Break(0 1)
Continue(0) Ret(0) InlineAsm(0) Mac(0) Struct(0 1 2) Repeat(0 1) Paren(0)
Continue(0) Ret(0) InlineAsm(0) MacCall(0) Struct(0 1 2) Repeat(0 1) Paren(0)
Try(0) Yield(0) Err);
spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1)
Fn(0 1 2) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(0 1) Enum(0 1)
Struct(0 1) Union(0 1) Trait(0 1 2 3 4) TraitAlias(0 1) Impl(0 1 2 3 4 5 6)
Mac(0) MacroDef(0));
spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1 2)
Fn(0 1 2 3) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(0 1 2 3) Enum(0 1)
Struct(0 1) Union(0 1) Trait(0 1 2 3 4) TraitAlias(0 1)
Impl(unsafety polarity defaultness constness generics of_trait self_ty items)
MacCall(0) MacroDef(0));
spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0) Byte(0) Char(0) Int(0 1)
Float(0 1) Bool(0) Err(0));
spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2) TupleStruct(0 1)
Or(0) Path(0 1) Tuple(0) Box(0) Ref(0 1) Lit(0) Range(0 1 2) Slice(0) Rest
Paren(0) Mac(0));
Paren(0) MacCall(0));
spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Rptr(0 1) BareFn(0) Never
Tup(0) Path(0 1) TraitObject(0 1) ImplTrait(0 1) Paren(0) Typeof(0) Infer
ImplicitSelf Mac(0) Err CVarArgs);
ImplicitSelf MacCall(0) Err CVarArgs);

impl SpanlessEq for Ident {
fn eq(&self, other: &Self) -> bool {
Expand Down
5 changes: 5 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ pub fn abort_after() -> usize {
Err(_) => usize::max_value(),
}
}

/// Are we running in travis-ci.org.
pub fn travis_ci() -> bool {
env::var_os("TRAVIS").is_some()
}
18 changes: 9 additions & 9 deletions tests/common/parse.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
extern crate rustc_ast;
extern crate rustc_expand;
extern crate rustc_parse as parse;
extern crate syntax;
extern crate syntax_expand;
extern crate syntax_pos;
extern crate rustc_session;
extern crate rustc_span;

use syntax::ast;
use syntax::ptr::P;
use syntax::sess::ParseSess;
use syntax::source_map::FilePathMapping;
use syntax_pos::FileName;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::FileName;

use std::panic;

pub fn libsyntax_expr(input: &str) -> Option<P<ast::Expr>> {
match panic::catch_unwind(|| {
let sess = ParseSess::new(FilePathMapping::empty());
sess.span_diagnostic.set_continue_after_error(false);
let e = parse::new_parser_from_source_str(
&sess,
FileName::Custom("test_precedence".to_string()),
Expand Down
132 changes: 105 additions & 27 deletions tests/repo/mod.rs
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
mod progress;

use self::progress::Progress;
use crate::common;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "7979016aff545f7b41cc517031026020b340989d";
const REVISION: &str = "2c462a2f776b899d46743b1b44eda976e846e61d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
let path = entry.path();
Expand All @@ -15,46 +19,115 @@ pub fn base_dir_filter(entry: &DirEntry) -> bool {
if path.extension().map(|e| e != "rs").unwrap_or(true) {
return false;
}
let path_string = path.to_string_lossy();
let path_string = if cfg!(windows) {
path_string.replace('\\', "/").into()
} else {
path_string
};

let mut path_string = path.to_string_lossy();
if cfg!(windows) {
path_string = path_string.replace('\\', "/").into();
}
assert!(path_string.starts_with("tests/rust/src/"));
let path = &path_string["tests/rust/src/".len()..];

// TODO assert that parsing fails on the parse-fail cases
if path_string.starts_with("tests/rust/src/test/parse-fail")
|| path_string.starts_with("tests/rust/src/test/compile-fail")
|| path_string.starts_with("tests/rust/src/test/rustfix")
if path.starts_with("test/parse-fail")
|| path.starts_with("test/compile-fail")
|| path.starts_with("test/rustfix")
{
return false;
}

if path_string.starts_with("tests/rust/src/test/ui") {
let stderr_path = path.with_extension("stderr");
if path.starts_with("test/ui") {
let stderr_path = entry.path().with_extension("stderr");
if stderr_path.exists() {
// Expected to fail in some way
return false;
}
}

match path_string.as_ref() {
match path {
// TODO: or-patterns patterns: `Some(1 | 8)`
// https://github.com/dtolnay/syn/issues/758
"test/mir-opt/exponential-or.rs" |
"test/ui/or-patterns/basic-switch.rs" |
"test/ui/or-patterns/basic-switchint.rs" |
"test/ui/or-patterns/bindings-runpass-1.rs" |
"test/ui/or-patterns/bindings-runpass-2.rs" |
"test/ui/or-patterns/consistent-bindings.rs" |
"test/ui/or-patterns/exhaustiveness-pass.rs" |
"test/ui/or-patterns/for-loop.rs" |
"test/ui/or-patterns/if-let-while-let.rs" |
"test/ui/or-patterns/issue-67514-irrefutable-param.rs" |
"test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs" |
"test/ui/or-patterns/let-pattern.rs" |
"test/ui/or-patterns/mix-with-wild.rs" |
"test/ui/or-patterns/or-patterns-default-binding-modes.rs" |
"test/ui/or-patterns/or-patterns-syntactic-pass.rs" |
"test/ui/or-patterns/search-via-bindings.rs" |
"test/ui/or-patterns/struct-like.rs" |

// TODO: inner attr in traits: `trait Foo { #![...] }`
// https://github.com/dtolnay/syn/issues/759
"test/pretty/trait-inner-attr.rs" |
"test/ui/parser/inner-attr-in-trait-def.rs" |

// TODO: const underscore in traits: `trait A { const _: (); }`
// https://github.com/dtolnay/syn/issues/760
"test/ui/parser/assoc-const-underscore-syntactic-pass.rs" |

// TODO: top level fn without body: `fn f();`
// https://github.com/dtolnay/syn/issues/761
"test/ui/parser/fn-body-optional-syntactic-pass.rs" |
"test/ui/parser/fn-header-syntactic-pass.rs" |

// TODO: extern static with value: `extern { static X: u8 = 0; }`
// https://github.com/dtolnay/syn/issues/762
"test/ui/parser/foreign-static-syntactic-pass.rs" |

// TODO: extern type with bound: `extern { type A: Ord; }`
// https://github.com/dtolnay/syn/issues/763
"test/ui/parser/foreign-ty-syntactic-pass.rs" |

// TODO: top level const/static without value: `const X: u8;`
// https://github.com/dtolnay/syn/issues/764
"test/ui/parser/item-free-const-no-body-syntactic-pass.rs" |
"test/ui/parser/item-free-static-no-body-syntactic-pass.rs" |

// TODO: mut receiver in fn pointer type: `fn(mut self)`
// https://github.com/dtolnay/syn/issues/765
"test/ui/parser/self-param-syntactic-pass.rs" |

// TODO: const trait impls and bounds
// https://github.com/dtolnay/syn/issues/766
// https://github.com/dtolnay/syn/issues/767
"test/ui/rfc-2632-const-trait-impl/assoc-type.rs" |
"test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs" |
"test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs" |
"test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs" |
"test/ui/rfc-2632-const-trait-impl/feature-gate.rs" |
"test/ui/rfc-2632-const-trait-impl/generic-bound.rs" |
"test/ui/rfc-2632-const-trait-impl/syntax.rs" |

// Deprecated placement syntax
"tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
"test/ui/obsolete-in-place/bad.rs" |

// Deprecated anonymous parameter syntax in traits
"tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
"tests/rust/src/test/ui/issues/issue-13105.rs" |
"tests/rust/src/test/ui/issues/issue-13775.rs" |
"tests/rust/src/test/ui/issues/issue-34074.rs" |
// Deprecated await macro syntax
"tests/rust/src/test/ui/async-await/await-macro.rs" |
"test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
"test/ui/issues/issue-13105.rs" |
"test/ui/issues/issue-13775.rs" |
"test/ui/issues/issue-34074.rs" |

// 2015-style dyn that libsyntax rejects
"tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
"test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |

// not actually test cases
"tests/rust/src/test/ui/include-single-expr-helper.rs" |
"tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
"tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
"tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
"tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
"test/rustdoc-ui/test-compile-fail2.rs" |
"test/rustdoc-ui/test-compile-fail3.rs" |
"test/ui/include-single-expr-helper.rs" |
"test/ui/include-single-expr-helper-1.rs" |
"test/ui/issues/auxiliary/issue-21146-inc.rs" |
"test/ui/json-bom-plus-crlf-multifile-aux.rs" |
"test/ui/macros/auxiliary/macro-comma-support.rs" |
"test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,

_ => true,
}
}
Expand All @@ -75,7 +148,8 @@ fn download_and_unpack() -> Result<()> {
REVISION
);
let response = reqwest::blocking::get(&url)?.error_for_status()?;
let decoder = GzDecoder::new(response);
let progress = Progress::new(response);
let decoder = GzDecoder::new(progress);
let mut archive = Archive::new(decoder);
let prefix = format!("rust-{}", REVISION);

Expand All @@ -93,6 +167,10 @@ fn download_and_unpack() -> Result<()> {
let relative = path.strip_prefix(&prefix)?;
let out = tests_rust.join(relative);
entry.unpack(&out)?;
if common::travis_ci() {
// Something about this makes the travis build not deadlock...
errorf!(".");
}
}

fs::write("tests/rust/COMMIT", REVISION)?;
Expand Down
37 changes: 37 additions & 0 deletions tests/repo/progress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::io::{Read, Result};
use std::time::{Duration, Instant};

pub struct Progress<R> {
bytes: usize,
tick: Instant,
stream: R,
}

impl<R> Progress<R> {
pub fn new(stream: R) -> Self {
Progress {
bytes: 0,
tick: Instant::now() + Duration::from_millis(2000),
stream,
}
}
}

impl<R: Read> Read for Progress<R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let num = self.stream.read(buf)?;
self.bytes += num;
let now = Instant::now();
if now > self.tick {
self.tick = now + Duration::from_millis(500);
errorf!("downloading... {} bytes\n", self.bytes);
}
Ok(num)
}
}

impl<R> Drop for Progress<R> {
fn drop(&mut self) {
errorf!("done ({} bytes)\n", self.bytes);
}
}
42 changes: 42 additions & 0 deletions tests/test_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,48 @@ fn test_bool_lit() {
"###);
}

#[test]
fn test_negative_lit() {
let meta = test("#[form(min = -1, max = 200)]");

snapshot!(meta, @r###"
Meta::List {
path: Path {
segments: [
PathSegment {
ident: "form",
arguments: None,
},
],
},
nested: [
Meta(Meta::NameValue {
path: Path {
segments: [
PathSegment {
ident: "min",
arguments: None,
},
],
},
lit: -1,
}),
Meta(Meta::NameValue {
path: Path {
segments: [
PathSegment {
ident: "max",
arguments: None,
},
],
},
lit: 200,
}),
],
}
"###);
}

fn test(input: &str) -> Meta {
let attrs = Attribute::parse_outer.parse_str(input).unwrap();

Expand Down
17 changes: 15 additions & 2 deletions tests/test_lit.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
mod features;

use proc_macro2::{TokenStream, TokenTree};
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::str::FromStr;
use syn::Lit;
use syn::{Lit, LitFloat, LitInt};

fn lit(s: &str) -> Lit {
match TokenStream::from_str(s)
Expand Down Expand Up @@ -182,3 +182,16 @@ fn floats() {
test_float("1.0__3e-12", 1.03e-12, "");
test_float("1.03e+12", 1.03e12, "");
}

#[test]
fn negative() {
let span = Span::call_site();
assert_eq!("-1", LitInt::new("-1", span).to_string());
assert_eq!("-1i8", LitInt::new("-1i8", span).to_string());
assert_eq!("-1i16", LitInt::new("-1i16", span).to_string());
assert_eq!("-1i32", LitInt::new("-1i32", span).to_string());
assert_eq!("-1i64", LitInt::new("-1i64", span).to_string());
assert_eq!("-1.5", LitFloat::new("-1.5", span).to_string());
assert_eq!("-1.5f32", LitFloat::new("-1.5f32", span).to_string());
assert_eq!("-1.5f64", LitFloat::new("-1.5f64", span).to_string());
}
103 changes: 65 additions & 38 deletions tests/test_precedence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,18 @@
//! spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate smallvec;
extern crate syntax;
extern crate syntax_pos;
extern crate rustc_span;

mod features;

use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use smallvec::smallvec;
use syntax::ast;
use syntax::ptr::P;
use syntax_pos::edition::Edition;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
Expand Down Expand Up @@ -167,7 +165,7 @@ fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
let mut passed = 0;
let mut failed = 0;

syntax::with_globals(Edition::Edition2018, || {
rustc_ast::with_globals(Edition::Edition2018, || {
for expr in exprs {
let raw = quote!(#expr).to_string();

Expand Down Expand Up @@ -210,17 +208,61 @@ fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
use rustc_ast::ast::{
Block, BorrowKind, Expr, ExprKind, Field, MacCall, Pat, Stmt, StmtKind, Ty,
};
use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::util::map_in_place::MapInPlace;
use rustc_data_structures::thin_vec::ThinVec;
use smallvec::SmallVec;
use rustc_span::DUMMY_SP;
use std::mem;
use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
use syntax::mut_visit::{noop_visit_expr, MutVisitor};
use syntax_pos::DUMMY_SP;

struct BracketsVisitor {
failed: bool,
};

fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> {
if f.is_shorthand {
noop_visit_expr(&mut f.expr, vis);
} else {
vis.visit_expr(&mut f.expr);
}
vec![f]
}

fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
let kind = match stmt.kind {
// Don't wrap toplevel expressions in statements.
StmtKind::Expr(mut e) => {
noop_visit_expr(&mut e, vis);
StmtKind::Expr(e)
}
StmtKind::Semi(mut e) => {
noop_visit_expr(&mut e, vis);
StmtKind::Semi(e)
}
s => s,
};

vec![Stmt { kind, ..stmt }]
}

fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
use rustc_ast::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs};
match &mut e.kind {
ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
ExprKind::Struct(path, fields, expr) => {
vis.visit_path(path);
fields.flat_map_in_place(|field| flat_map_field(field, vis));
visit_opt(expr, |expr| vis.visit_expr(expr));
vis.visit_id(&mut e.id);
vis.visit_span(&mut e.span);
visit_thin_attrs(&mut e.attrs, vis);
}
_ => noop_visit_expr(e, vis),
}
}

impl MutVisitor for BracketsVisitor {
fn visit_expr(&mut self, e: &mut P<Expr>) {
noop_visit_expr(e, self);
Expand All @@ -241,13 +283,12 @@ fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>>
}
}

fn flat_map_field(&mut self, mut f: Field) -> SmallVec<[Field; 1]> {
if f.is_shorthand {
noop_visit_expr(&mut f.expr, self);
} else {
self.visit_expr(&mut f.expr);
}
SmallVec::from([f])
fn visit_block(&mut self, block: &mut P<Block>) {
self.visit_id(&mut block.id);
block
.stmts
.flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
self.visit_span(&mut block.span);
}

// We don't want to look at expressions that might appear in patterns or
Expand All @@ -261,24 +302,7 @@ fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>>
let _ = ty;
}

fn flat_map_stmt(&mut self, stmt: Stmt) -> SmallVec<[Stmt; 1]> {
let kind = match stmt.kind {
// Don't wrap toplevel expressions in statements.
StmtKind::Expr(mut e) => {
noop_visit_expr(&mut e, self);
StmtKind::Expr(e)
}
StmtKind::Semi(mut e) => {
noop_visit_expr(&mut e, self);
StmtKind::Semi(e)
}
s => s,
};

smallvec![Stmt { kind, ..stmt }]
}

fn visit_mac(&mut self, mac: &mut Mac) {
fn visit_mac(&mut self, mac: &mut MacCall) {
// By default when folding over macros, libsyntax panics. This is
// because it's usually not what you want, you want to run after
// macro expansion. We do want to do that (syn doesn't do macro
Expand Down Expand Up @@ -354,7 +378,10 @@ fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
struct CollectExprs(Vec<Expr>);
impl Fold for CollectExprs {
fn fold_expr(&mut self, expr: Expr) -> Expr {
self.0.push(expr);
match expr {
Expr::Verbatim(tokens) if tokens.is_empty() => {}
_ => self.0.push(expr),
}

Expr::Tuple(ExprTuple {
attrs: vec![],
Expand Down
22 changes: 12 additions & 10 deletions tests/test_round_trip.rs
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@
#![recursion_limit = "1024"]
#![feature(rustc_private)]

extern crate rustc_ast;
extern crate rustc_errors;
extern crate rustc_expand;
extern crate rustc_parse as parse;
extern crate syntax;
extern crate syntax_expand;
extern crate syntax_pos;
extern crate rustc_session;
extern crate rustc_span;

mod features;

use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use syntax::ast;
use syntax::errors::PResult;
use syntax::sess::ParseSess;
use syntax::source_map::FilePathMapping;
use syntax_pos::edition::Edition;
use syntax_pos::FileName;
use rustc_ast::ast;
use rustc_errors::PResult;
use rustc_session::parse::ParseSess;
use rustc_span::edition::Edition;
use rustc_span::source_map::FilePathMapping;
use rustc_span::FileName;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
Expand Down Expand Up @@ -78,7 +80,7 @@ fn test_round_trip() {
let back = quote!(#krate).to_string();

let equal = panic::catch_unwind(|| {
syntax::with_globals(Edition::Edition2018, || {
rustc_ast::with_globals(Edition::Edition2018, || {
let sess = ParseSess::new(FilePathMapping::empty());
let before = match libsyntax_parse(content, &sess) {
Ok(before) => before,
Expand Down
44 changes: 44 additions & 0 deletions tests/test_stmt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#[macro_use]
mod macros;

use syn::Stmt;

#[test]
fn test_raw_operator() {
let stmt = syn::parse_str::<Stmt>("let _ = &raw const x;").unwrap();

snapshot!(stmt, @r###"
Local(Local {
pat: Pat::Wild,
init: Some(Verbatim(`& raw const x`)),
})
"###);
}

#[test]
fn test_raw_variable() {
let stmt = syn::parse_str::<Stmt>("let _ = &raw;").unwrap();

snapshot!(stmt, @r###"
Local(Local {
pat: Pat::Wild,
init: Some(Expr::Reference {
expr: Expr::Path {
path: Path {
segments: [
PathSegment {
ident: "raw",
arguments: None,
},
],
},
},
}),
})
"###);
}

#[test]
fn test_raw_invalid() {
assert!(syn::parse_str::<Stmt>("let _ = &raw x;").is_err());
}