Skip to content

Commit

Permalink
Merge pull request #1236 from CAD97/cursor-cmp
Browse files Browse the repository at this point in the history
Implement `PartialOrd` for `Cursor`
  • Loading branch information
dtolnay authored Oct 20, 2022
2 parents a807b16 + f6a43aa commit 2b3f742
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 4 deletions.
14 changes: 11 additions & 3 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use crate::proc_macro as pm;
use crate::Lifetime;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::marker::PhantomData;
use std::{cmp::Ordering, marker::PhantomData};

/// Internal type which is used instead of `TokenTree` to represent a token tree
/// within a `TokenBuffer`.
Expand Down Expand Up @@ -348,8 +348,16 @@ impl<'a> Eq for Cursor<'a> {}
impl<'a> PartialEq for Cursor<'a> {
fn eq(&self, other: &Self) -> bool {
let Cursor { ptr, scope, marker } = self;
let _ = marker;
*ptr == other.ptr && *scope == other.scope
let _ = (scope, marker);
*ptr == other.ptr
}
}

impl<'a> PartialOrd for Cursor<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let Cursor { ptr, scope, marker } = self;
let _ = (scope, marker);
ptr.partial_cmp(&other.ptr)
}
}

Expand Down
18 changes: 17 additions & 1 deletion src/verbatim.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::parse::{ParseBuffer, ParseStream};
use proc_macro2::TokenStream;
use proc_macro2::{Delimiter, TokenStream};
use std::iter;

pub fn between<'a>(begin: ParseBuffer<'a>, end: ParseStream<'a>) -> TokenStream {
Expand All @@ -8,6 +8,22 @@ pub fn between<'a>(begin: ParseBuffer<'a>, end: ParseStream<'a>) -> TokenStream
let mut tokens = TokenStream::new();
while cursor != end {
let (tt, next) = cursor.token_tree().unwrap();

if next > end {
// In some edge cases, a syntax node can actually cross the border
// of a None-delimited group, due to such groups being transparent
// to the parser in most cases. In the cases that this can occur,
// the presence of the group is known to be semantically irrelevant,
// so we should just ignore the presence of the group. (Issue #1235)
if let Some((inside, _span, after)) = cursor.group(Delimiter::None) {
assert!(next == after);
cursor = inside;
continue;
} else {
panic!("verbatim end must not be inside a delimited group");
}
}

tokens.extend(iter::once(tt));
cursor = next;
}
Expand Down
32 changes: 32 additions & 0 deletions tests/regression/issue1235.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use proc_macro2::{Delimiter, Group};
use quote::quote;

#[test]
fn main() {
// Okay. Rustc allows top-level `static` with no value syntactically, but
// not semantically. Syn parses as Item::Verbatim.
let tokens = quote!(
pub static FOO: usize;
pub static BAR: usize;
);
let file = syn::parse2::<syn::File>(tokens).unwrap();
println!("{:#?}", file);

// Okay.
let inner = Group::new(
Delimiter::None,
quote!(static FOO: usize = 0; pub static BAR: usize = 0),
);
let tokens = quote!(pub #inner;);
let file = syn::parse2::<syn::File>(tokens).unwrap();
println!("{:#?}", file);

// Parser crash.
let inner = Group::new(
Delimiter::None,
quote!(static FOO: usize; pub static BAR: usize),
);
let tokens = quote!(pub #inner;);
let file = syn::parse2::<syn::File>(tokens).unwrap();
println!("{:#?}", file);
}

0 comments on commit 2b3f742

Please sign in to comment.