Skip to content

Commit 63a5bbd

Browse files
committed
hygiene: Eliminate expansion hierarchy in favor of call-site hierarchy
1 parent a32e979 commit 63a5bbd

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

src/libsyntax_pos/hygiene.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ pub struct SyntaxContextData {
4141
pub struct Mark(u32);
4242

4343
struct MarkData {
44-
parent: Mark,
4544
kind: MarkKind,
4645
expn_info: Option<ExpnInfo>,
4746
}
@@ -54,9 +53,9 @@ pub enum MarkKind {
5453
}
5554

5655
impl Mark {
57-
pub fn fresh(parent: Mark) -> Self {
56+
pub fn fresh(_parent: Mark) -> Self {
5857
HygieneData::with(|data| {
59-
data.marks.push(MarkData { parent: parent, kind: MarkKind::Legacy, expn_info: None });
58+
data.marks.push(MarkData { kind: MarkKind::Legacy, expn_info: None });
6059
Mark(data.marks.len() as u32 - 1)
6160
})
6261
}
@@ -93,7 +92,8 @@ impl Mark {
9392
if self == Mark::root() || data.marks[self.0 as usize].kind == MarkKind::Modern {
9493
return self;
9594
}
96-
self = data.marks[self.0 as usize].parent;
95+
96+
self = self.call_site_mark(data);
9797
}
9898
})
9999
}
@@ -114,7 +114,8 @@ impl Mark {
114114
if self == Mark::root() {
115115
return false;
116116
}
117-
self = data.marks[self.0 as usize].parent;
117+
118+
self = self.call_site_mark(data);
118119
}
119120
true
120121
})
@@ -134,17 +135,25 @@ impl Mark {
134135
let mut a_path = FxHashSet::<Mark>();
135136
while a != Mark::root() {
136137
a_path.insert(a);
137-
a = data.marks[a.0 as usize].parent;
138+
139+
a = a.call_site_mark(data);
138140
}
139141

140142
// While the path from b to the root hasn't intersected, move up the tree
141143
while !a_path.contains(&b) {
142-
b = data.marks[b.0 as usize].parent;
144+
b = b.call_site_mark(data);
143145
}
144146

145147
b
146148
})
147149
}
150+
151+
/// Private helpers not acquiring a lock around global data
152+
fn call_site_mark(self, data: &HygieneData) -> Mark {
153+
data.marks[self.0 as usize].expn_info.as_ref()
154+
.map(|einfo| data.syntax_contexts[einfo.call_site.ctxt().0 as usize].outer_mark)
155+
.unwrap_or(Mark::root())
156+
}
148157
}
149158

150159
pub struct HygieneData {
@@ -159,7 +168,6 @@ impl HygieneData {
159168
pub fn new() -> Self {
160169
HygieneData {
161170
marks: vec![MarkData {
162-
parent: Mark::root(),
163171
kind: MarkKind::Builtin,
164172
expn_info: None,
165173
}],
@@ -198,14 +206,13 @@ impl SyntaxContext {
198206

199207
// Allocate a new SyntaxContext with the given ExpnInfo. This is used when
200208
// deserializing Spans from the incr. comp. cache.
201-
// FIXME(mw): This method does not restore MarkData::parent or
202-
// SyntaxContextData::prev_ctxt or SyntaxContextData::modern. These things
209+
// FIXME(mw): This method does not restore SyntaxContextData::prev_ctxt or
210+
// SyntaxContextData::modern. These things
203211
// don't seem to be used after HIR lowering, so everything should be fine
204212
// as long as incremental compilation does not kick in before that.
205213
pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
206214
HygieneData::with(|data| {
207215
data.marks.push(MarkData {
208-
parent: Mark::root(),
209216
kind: MarkKind::Legacy,
210217
expn_info: Some(expansion_info)
211218
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-pass
12+
13+
#![feature(decl_macro)]
14+
15+
macro_rules! define_field {
16+
() => {
17+
struct S { field: u8 }
18+
}
19+
}
20+
21+
macro use_field($define_field: item) {
22+
$define_field
23+
24+
// OK, both struct name `S` and field `name` resolve to definitions produced by `define_field`
25+
// and living in the "root" context that is in scope at `use_field`'s def-site.
26+
fn f() { S { field: 0 }; }
27+
}
28+
29+
use_field!(define_field!{});
30+
31+
fn main() {}

0 commit comments

Comments
 (0)