summaryrefslogtreecommitdiffstats
path: root/vendor/syn/src/buffer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/syn/src/buffer.rs')
-rw-r--r--vendor/syn/src/buffer.rs102
1 files changed, 66 insertions, 36 deletions
diff --git a/vendor/syn/src/buffer.rs b/vendor/syn/src/buffer.rs
index 2cb6690f0..2c8e21bdb 100644
--- a/vendor/syn/src/buffer.rs
+++ b/vendor/syn/src/buffer.rs
@@ -14,7 +14,9 @@
use crate::proc_macro as pm;
use crate::Lifetime;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+use std::hint;
use std::marker::PhantomData;
+use std::mem;
use std::ptr;
use std::slice;
@@ -57,29 +59,39 @@ impl TokenBuffer {
// NOTE: Do not mutate the Vec returned from this function once it returns;
// the address of its backing memory must remain stable.
fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
- // Build up the entries list, recording the locations of any Groups
- // in the list to be processed later.
- let mut entries = Vec::new();
- let mut groups = Vec::new();
- for tt in stream {
+ let iterator = stream.into_iter();
+ let mut entries = Vec::with_capacity(iterator.size_hint().0 + 1);
+ let mut next_index_after_last_group = 0;
+ for tt in iterator {
match tt {
- TokenTree::Ident(sym) => {
- entries.push(Entry::Ident(sym));
+ TokenTree::Ident(ident) => {
+ entries.push(Entry::Ident(ident));
}
- TokenTree::Punct(op) => {
- entries.push(Entry::Punct(op));
+ TokenTree::Punct(punct) => {
+ entries.push(Entry::Punct(punct));
}
- TokenTree::Literal(l) => {
- entries.push(Entry::Literal(l));
+ TokenTree::Literal(literal) => {
+ entries.push(Entry::Literal(literal));
}
- TokenTree::Group(g) => {
- // Record the index of the interesting entry, and store an
- // `End(null)` there temporarily.
- groups.push((entries.len(), g));
- entries.push(Entry::End(ptr::null()));
+ TokenTree::Group(group) => {
+ // We cannot fill in a real `End` pointer until `entries` is
+ // finished growing and getting potentially reallocated.
+ // Instead, we temporarily coopt the spot where the end
+ // pointer would go, and use it to string together an
+ // intrusive linked list of all the Entry::Group entries in
+ // the vector. Later after `entries` is done growing, we'll
+ // traverse the linked list and fill in all the end
+ // pointers with a correct value.
+ let group_up =
+ ptr::null::<u8>().wrapping_add(next_index_after_last_group) as *const Entry;
+
+ let inner = Self::inner_new(group.stream(), group_up);
+ entries.push(Entry::Group(group, inner));
+ next_index_after_last_group = entries.len();
}
}
}
+
// Add an `End` entry to the end with a reference to the enclosing token
// stream which was passed in.
entries.push(Entry::End(up));
@@ -90,20 +102,36 @@ impl TokenBuffer {
// pointer into it.
let entries = entries.into_boxed_slice();
let len = entries.len();
+
// Convert boxed slice into a pointer to the first element early, to
// avoid invalidating pointers into this slice when we move the Box.
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
let entries = Box::into_raw(entries) as *mut Entry;
- for (idx, group) in groups {
- // We know that this index refers to one of the temporary
- // `End(null)` entries, and we know that the last entry is
- // `End(up)`, so the next index is also valid.
- let group_up = unsafe { entries.add(idx + 1) };
-
- // The end entry stored at the end of this Entry::Group should
- // point to the Entry which follows the Group in the list.
- let inner = Self::inner_new(group.stream(), group_up);
- unsafe { *entries.add(idx) = Entry::Group(group, inner) };
+
+ // Traverse intrusive linked list of Entry::Group entries and fill in
+ // correct End pointers.
+ while let Some(idx) = next_index_after_last_group.checked_sub(1) {
+ // We know that idx refers to one of the Entry::Group entries, and
+ // that the very last entry is an Entry::End, so the next index
+ // after any group entry is a valid index.
+ let group_up = unsafe { entries.add(next_index_after_last_group) };
+
+ // Linked list only takes us to entries which are of type Group.
+ let token_buffer = match unsafe { &*entries.add(idx) } {
+ Entry::Group(_group, token_buffer) => token_buffer,
+ _ => unsafe { hint::unreachable_unchecked() },
+ };
+
+ // Last entry in any TokenBuffer is of type End.
+ let buffer_ptr = token_buffer.ptr as *mut Entry;
+ let last_entry = unsafe { &mut *buffer_ptr.add(token_buffer.len - 1) };
+ let end_ptr_slot = match last_entry {
+ Entry::End(end_ptr_slot) => end_ptr_slot,
+ _ => unsafe { hint::unreachable_unchecked() },
+ };
+
+ // Step to next element in linked list.
+ next_index_after_last_group = mem::replace(end_ptr_slot, group_up) as usize;
}
TokenBuffer { ptr: entries, len }
@@ -275,7 +303,9 @@ impl<'a> Cursor<'a> {
pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
self.ignore_none();
match self.entry() {
- Entry::Punct(op) if op.as_char() != '\'' => Some((op.clone(), unsafe { self.bump() })),
+ Entry::Punct(punct) if punct.as_char() != '\'' => {
+ Some((punct.clone(), unsafe { self.bump() }))
+ }
_ => None,
}
}
@@ -285,7 +315,7 @@ impl<'a> Cursor<'a> {
pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
self.ignore_none();
match self.entry() {
- Entry::Literal(lit) => Some((lit.clone(), unsafe { self.bump() })),
+ Entry::Literal(literal) => Some((literal.clone(), unsafe { self.bump() })),
_ => None,
}
}
@@ -295,12 +325,12 @@ impl<'a> Cursor<'a> {
pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
self.ignore_none();
match self.entry() {
- Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
+ Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => {
let next = unsafe { self.bump() };
match next.ident() {
Some((ident, rest)) => {
let lifetime = Lifetime {
- apostrophe: op.span(),
+ apostrophe: punct.span(),
ident,
};
Some((lifetime, rest))
@@ -334,9 +364,9 @@ impl<'a> Cursor<'a> {
pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
let tree = match self.entry() {
Entry::Group(group, _) => group.clone().into(),
- Entry::Literal(lit) => lit.clone().into(),
+ Entry::Literal(literal) => literal.clone().into(),
Entry::Ident(ident) => ident.clone().into(),
- Entry::Punct(op) => op.clone().into(),
+ Entry::Punct(punct) => punct.clone().into(),
Entry::End(..) => return None,
};
@@ -348,9 +378,9 @@ impl<'a> Cursor<'a> {
pub fn span(self) -> Span {
match self.entry() {
Entry::Group(group, _) => group.span(),
- Entry::Literal(l) => l.span(),
- Entry::Ident(t) => t.span(),
- Entry::Punct(o) => o.span(),
+ Entry::Literal(literal) => literal.span(),
+ Entry::Ident(ident) => ident.span(),
+ Entry::Punct(punct) => punct.span(),
Entry::End(..) => Span::call_site(),
}
}
@@ -364,7 +394,7 @@ impl<'a> Cursor<'a> {
Entry::End(..) => None,
// Treat lifetimes as a single tt for the purposes of 'skip'.
- Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
+ Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => {
let next = unsafe { self.bump() };
match next.entry() {
Entry::Ident(_) => Some(unsafe { next.bump() }),