Skip to content

Commit d8f4c9f

Browse files
committed
Auto merge of #55525 - nnethercote:MatcherPos-stack-SmallVec, r=nnethercote
Make `MatcherPos::stack` a `SmallVec`. This avoids some allocations. This seems like a trivial change, but the compiler rejects it: ``` Compiling syntax v0.0.0 (/home/njn/moz/rust1/src/libsyntax) error[E0597]: `initial` does not live long enough=========> ] 89/110: syntax --> libsyntax/ext/tt/macro_parser.rs:647:57 | 647 | let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)]; | ^^^^^^^^^^^^ borrowed value does not live long enough ... 762 | } | - | | | `initial` dropped here while still borrowed | borrow later used here, when `initial` is dropped error: aborting due to previous error ``` This is either a compiler bug, or there's some subtle thing I don't understand. The lifetimes sure seem straightforward: `initial` is declared, and then `cur_items` is declared immediately afterward, and it uses a reference to `initial`. The error message makes it sound like the compiler is dropping the variables in the wrong order. r? @nikomatsakis, any idea what the problem is?
2 parents 775eab5 + 68e76dc commit d8f4c9f

File tree

1 file changed

+57
-34
lines changed

1 file changed

+57
-34
lines changed

src/libsyntax/ext/tt/macro_parser.rs

+57-34
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ use std::rc::Rc;
107107
/// Either a sequence of token trees or a single one. This is used as the representation of the
108108
/// sequence of tokens that make up a matcher.
109109
#[derive(Clone)]
110-
enum TokenTreeOrTokenTreeSlice<'a> {
110+
enum TokenTreeOrTokenTreeSlice<'tt> {
111111
Tt(TokenTree),
112-
TtSeq(&'a [TokenTree]),
112+
TtSeq(&'tt [TokenTree]),
113113
}
114114

115-
impl<'a> TokenTreeOrTokenTreeSlice<'a> {
115+
impl<'tt> TokenTreeOrTokenTreeSlice<'tt> {
116116
/// Returns the number of constituent top-level token trees of `self` (top-level in that it
117117
/// will not recursively descend into subtrees).
118118
fn len(&self) -> usize {
@@ -136,23 +136,41 @@ impl<'a> TokenTreeOrTokenTreeSlice<'a> {
136136
/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
137137
/// descended into.
138138
#[derive(Clone)]
139-
struct MatcherTtFrame<'a> {
139+
struct MatcherTtFrame<'tt> {
140140
/// The "parent" matcher that we are descending into.
141-
elts: TokenTreeOrTokenTreeSlice<'a>,
141+
elts: TokenTreeOrTokenTreeSlice<'tt>,
142142
/// The position of the "dot" in `elts` at the time we descended.
143143
idx: usize,
144144
}
145145

146146
type NamedMatchVec = SmallVec<[NamedMatch; 4]>;
147147

148-
/// Represents a single "position" (aka "matcher position", aka "item"), as described in the module
149-
/// documentation.
148+
/// Represents a single "position" (aka "matcher position", aka "item"), as
149+
/// described in the module documentation.
150+
///
151+
/// Here:
152+
///
153+
/// - `'root` represents the lifetime of the stack slot that holds the root
154+
/// `MatcherPos`. As described in `MatcherPosHandle`, the root `MatcherPos`
155+
/// structure is stored on the stack, but subsequent instances are put into
156+
/// the heap.
157+
/// - `'tt` represents the lifetime of the token trees that this matcher
158+
/// position refers to.
159+
///
160+
/// It is important to distinguish these two lifetimes because we have a
161+
/// `SmallVec<TokenTreeOrTokenTreeSlice<'tt>>` below, and the destructor of
162+
/// that is considered to possibly access the data from its elements (it lacks
163+
/// a `#[may_dangle]` attribute). As a result, the compiler needs to know that
164+
/// all the elements in that `SmallVec` strictly outlive the root stack slot
165+
/// lifetime. By separating `'tt` from `'root`, we can show that.
150166
#[derive(Clone)]
151-
struct MatcherPos<'a> {
167+
struct MatcherPos<'root, 'tt: 'root> {
152168
/// The token or sequence of tokens that make up the matcher
153-
top_elts: TokenTreeOrTokenTreeSlice<'a>,
169+
top_elts: TokenTreeOrTokenTreeSlice<'tt>,
170+
154171
/// The position of the "dot" in this matcher
155172
idx: usize,
173+
156174
/// The first span of source source that the beginning of this matcher corresponds to. In other
157175
/// words, the token in the source whose span is `sp_open` is matched against the first token of
158176
/// the matcher.
@@ -182,26 +200,31 @@ struct MatcherPos<'a> {
182200
/// in this matcher.
183201
match_hi: usize,
184202

185-
// Specifically used if we are matching a repetition. If we aren't both should be `None`.
203+
// The following fields are used if we are matching a repetition. If we aren't, they should be
204+
// `None`.
205+
186206
/// The KleeneOp of this sequence if we are in a repetition.
187207
seq_op: Option<quoted::KleeneOp>,
188-
/// The separator if we are in a repetition
208+
209+
/// The separator if we are in a repetition.
189210
sep: Option<Token>,
211+
190212
/// The "parent" matcher position if we are in a repetition. That is, the matcher position just
191213
/// before we enter the sequence.
192-
up: Option<MatcherPosHandle<'a>>,
214+
up: Option<MatcherPosHandle<'root, 'tt>>,
193215

194-
// Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
195-
// a delimited token tree (e.g. something wrapped in `(` `)`) or to get the contents of a doc
196-
// comment...
216+
/// Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
217+
/// a delimited token tree (e.g. something wrapped in `(` `)`) or to get the contents of a doc
218+
/// comment...
219+
///
197220
/// When matching against matchers with nested delimited submatchers (e.g. `pat ( pat ( .. )
198221
/// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
199222
/// that where the bottom of the stack is the outermost matcher.
200-
// Also, throughout the comments, this "descent" is often referred to as "unzipping"...
201-
stack: Vec<MatcherTtFrame<'a>>,
223+
/// Also, throughout the comments, this "descent" is often referred to as "unzipping"...
224+
stack: SmallVec<[MatcherTtFrame<'tt>; 1]>,
202225
}
203226

204-
impl<'a> MatcherPos<'a> {
227+
impl<'root, 'tt> MatcherPos<'root, 'tt> {
205228
/// Add `m` as a named match for the `idx`-th metavar.
206229
fn push_match(&mut self, idx: usize, m: NamedMatch) {
207230
let matches = Rc::make_mut(&mut self.matches[idx]);
@@ -218,12 +241,12 @@ impl<'a> MatcherPos<'a> {
218241
// Therefore, the initial MatcherPos is always allocated on the stack,
219242
// subsequent ones (of which there aren't that many) are allocated on the heap,
220243
// and this type is used to encapsulate both cases.
221-
enum MatcherPosHandle<'a> {
222-
Ref(&'a mut MatcherPos<'a>),
223-
Box(Box<MatcherPos<'a>>),
244+
enum MatcherPosHandle<'root, 'tt: 'root> {
245+
Ref(&'root mut MatcherPos<'root, 'tt>),
246+
Box(Box<MatcherPos<'root, 'tt>>),
224247
}
225248

226-
impl<'a> Clone for MatcherPosHandle<'a> {
249+
impl<'root, 'tt> Clone for MatcherPosHandle<'root, 'tt> {
227250
// This always produces a new Box.
228251
fn clone(&self) -> Self {
229252
MatcherPosHandle::Box(match *self {
@@ -233,8 +256,8 @@ impl<'a> Clone for MatcherPosHandle<'a> {
233256
}
234257
}
235258

236-
impl<'a> Deref for MatcherPosHandle<'a> {
237-
type Target = MatcherPos<'a>;
259+
impl<'root, 'tt> Deref for MatcherPosHandle<'root, 'tt> {
260+
type Target = MatcherPos<'root, 'tt>;
238261
fn deref(&self) -> &Self::Target {
239262
match *self {
240263
MatcherPosHandle::Ref(ref r) => r,
@@ -243,8 +266,8 @@ impl<'a> Deref for MatcherPosHandle<'a> {
243266
}
244267
}
245268

246-
impl<'a> DerefMut for MatcherPosHandle<'a> {
247-
fn deref_mut(&mut self) -> &mut MatcherPos<'a> {
269+
impl<'root, 'tt> DerefMut for MatcherPosHandle<'root, 'tt> {
270+
fn deref_mut(&mut self) -> &mut MatcherPos<'root, 'tt> {
248271
match *self {
249272
MatcherPosHandle::Ref(ref mut r) => r,
250273
MatcherPosHandle::Box(ref mut b) => b,
@@ -292,7 +315,7 @@ fn create_matches(len: usize) -> Box<[Rc<NamedMatchVec>]> {
292315

293316
/// Generate the top-level matcher position in which the "dot" is before the first token of the
294317
/// matcher `ms` and we are going to start matching at the span `open` in the source.
295-
fn initial_matcher_pos(ms: &[TokenTree], open: Span) -> MatcherPos {
318+
fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherPos<'root, 'tt> {
296319
let match_idx_hi = count_names(ms);
297320
let matches = create_matches(match_idx_hi);
298321
MatcherPos {
@@ -312,7 +335,7 @@ fn initial_matcher_pos(ms: &[TokenTree], open: Span) -> MatcherPos {
312335
match_hi: match_idx_hi,
313336

314337
// Haven't descended into any delimiters, so empty stack
315-
stack: vec![],
338+
stack: smallvec![],
316339

317340
// Haven't descended into any sequences, so both of these are `None`.
318341
seq_op: None,
@@ -445,12 +468,12 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
445468
/// # Returns
446469
///
447470
/// A `ParseResult`. Note that matches are kept track of through the items generated.
448-
fn inner_parse_loop<'a>(
471+
fn inner_parse_loop<'root, 'tt>(
449472
sess: &ParseSess,
450-
cur_items: &mut SmallVec<[MatcherPosHandle<'a>; 1]>,
451-
next_items: &mut Vec<MatcherPosHandle<'a>>,
452-
eof_items: &mut SmallVec<[MatcherPosHandle<'a>; 1]>,
453-
bb_items: &mut SmallVec<[MatcherPosHandle<'a>; 1]>,
473+
cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
474+
next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
475+
eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
476+
bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
454477
token: &Token,
455478
span: syntax_pos::Span,
456479
) -> ParseResult<()> {
@@ -554,7 +577,7 @@ fn inner_parse_loop<'a>(
554577

555578
let matches = create_matches(item.matches.len());
556579
cur_items.push(MatcherPosHandle::Box(Box::new(MatcherPos {
557-
stack: vec![],
580+
stack: smallvec![],
558581
sep: seq.separator.clone(),
559582
seq_op: Some(seq.op),
560583
idx: 0,

0 commit comments

Comments
 (0)