Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement PartialOrd for Cursor #1236

Merged
merged 3 commits into from Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/buffer.rs
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
@@ -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
@@ -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);
}