Skip to content

Commit 36a4af4

Browse files
committed
Remove __extensions__ in names for a "pretty name"
As with the previous commit, this is targeted at removing the possibility of collisions between statics. The main use case here is when there's a type-parametric function with an inner static that's compiled as a library. Before this commit, any impl would generate a path item of "__extensions__". This changes this identifier to be a "pretty name", which is either the last element of the path of the trait implemented or the last element of the type's path that's being implemented. That doesn't quite cut it though, so the (trait, type) pair is hashed and again used to append information to the symbol. Essentially, __extensions__ was removed for something nicer for debugging, and then some more information was added to symbol name by including a hash of the trait being implemented and type it's being implemented for. This should prevent colliding names for inner statics in regular functions with similar names.
1 parent 4600212 commit 36a4af4

File tree

10 files changed

+135
-22
lines changed

10 files changed

+135
-22
lines changed

src/librustc/back/link.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use std::run;
3535
use std::str;
3636
use std::vec;
3737
use syntax::ast;
38-
use syntax::ast_map::{path, path_mod, path_name};
38+
use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
3939
use syntax::attr;
4040
use syntax::attr::{AttrMetaMethods};
4141
use syntax::print::pprust;
@@ -741,19 +741,40 @@ pub fn sanitize(s: &str) -> ~str {
741741
}
742742

743743
pub fn mangle(sess: Session, ss: path) -> ~str {
744-
// Follow C++ namespace-mangling style
744+
// Follow C++ namespace-mangling style, see
745+
// http://en.wikipedia.org/wiki/Name_mangling for more info.
745746

746-
let mut n = ~"_ZN"; // Begin name-sequence.
747+
let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested
747748

749+
// First, connect each component with <len, name> pairs.
748750
for s in ss.iter() {
749751
match *s {
750-
path_name(s) | path_mod(s) => {
752+
path_name(s) | path_mod(s) | path_pretty_name(s, _) => {
751753
let sani = sanitize(sess.str_of(s));
752754
n.push_str(fmt!("%u%s", sani.len(), sani));
753755
}
754756
}
755757
}
756758
n.push_char('E'); // End name-sequence.
759+
760+
// next, if any identifiers are "pretty" and need extra information tacked
761+
// on, then use the hash to generate two unique characters. For now
762+
// hopefully 2 characters is enough to avoid collisions.
763+
static EXTRA_CHARS: &'static str =
764+
"abcdefghijklmnopqrstuvwxyz\
765+
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
766+
0123456789";
767+
for s in ss.iter() {
768+
match *s {
769+
path_pretty_name(_, extra) => {
770+
let hi = (extra >> 32) as u32 as uint;
771+
let lo = extra as u32 as uint;
772+
n.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char);
773+
n.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char);
774+
}
775+
_ => {}
776+
}
777+
}
757778
n
758779
}
759780

src/librustc/metadata/common.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ pub static tag_impls_impl: uint = 0x84;
188188
pub static tag_items_data_item_inherent_impl: uint = 0x85;
189189
pub static tag_items_data_item_extension_impl: uint = 0x86;
190190

191+
pub static tag_path_elt_pretty_name: uint = 0x87;
192+
pub static tag_path_elt_pretty_name_ident: uint = 0x88;
193+
pub static tag_path_elt_pretty_name_extra: uint = 0x89;
194+
191195
pub struct LinkMeta {
192196
name: @str,
193197
vers: @str,

src/librustc/metadata/decoder.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,15 @@ fn item_path(item_doc: ebml::Doc) -> ast_map::path {
303303
} else if tag == tag_path_elt_name {
304304
let str = elt_doc.as_str_slice();
305305
result.push(ast_map::path_name(token::str_to_ident(str)));
306+
} else if tag == tag_path_elt_pretty_name {
307+
let name_doc = reader::get_doc(elt_doc,
308+
tag_path_elt_pretty_name_ident);
309+
let extra_doc = reader::get_doc(elt_doc,
310+
tag_path_elt_pretty_name_extra);
311+
let str = name_doc.as_str_slice();
312+
let extra = reader::doc_as_u64(extra_doc);
313+
result.push(ast_map::path_pretty_name(token::str_to_ident(str),
314+
extra));
306315
} else {
307316
// ignore tag_path_len element
308317
}

src/librustc/metadata/encoder.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,21 @@ fn encode_path(ecx: &EncodeContext,
358358
fn encode_path_elt(ecx: &EncodeContext,
359359
ebml_w: &mut writer::Encoder,
360360
elt: ast_map::path_elt) {
361-
let (tag, name) = match elt {
362-
ast_map::path_mod(name) => (tag_path_elt_mod, name),
363-
ast_map::path_name(name) => (tag_path_elt_name, name)
364-
};
365-
366-
ebml_w.wr_tagged_str(tag, ecx.tcx.sess.str_of(name));
361+
match elt {
362+
ast_map::path_mod(n) => {
363+
ebml_w.wr_tagged_str(tag_path_elt_mod, ecx.tcx.sess.str_of(n));
364+
}
365+
ast_map::path_name(n) => {
366+
ebml_w.wr_tagged_str(tag_path_elt_name, ecx.tcx.sess.str_of(n));
367+
}
368+
ast_map::path_pretty_name(n, extra) => {
369+
ebml_w.start_tag(tag_path_elt_pretty_name);
370+
ebml_w.wr_tagged_str(tag_path_elt_pretty_name_ident,
371+
ecx.tcx.sess.str_of(n));
372+
ebml_w.wr_tagged_u64(tag_path_elt_pretty_name_extra, extra);
373+
ebml_w.end_tag();
374+
}
375+
}
367376
}
368377

369378
ebml_w.start_tag(tag_path);

src/librustc/middle/trans/common.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,8 @@ pub fn path_str(sess: session::Session, p: &[path_elt]) -> ~str {
947947
let mut first = true;
948948
for e in p.iter() {
949949
match *e {
950-
ast_map::path_name(s) | ast_map::path_mod(s) => {
950+
ast_map::path_name(s) | ast_map::path_mod(s) |
951+
ast_map::path_pretty_name(s, _) => {
951952
if first {
952953
first = false
953954
} else {

src/librustc/middle/trans/meth.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use middle::trans::type_::Type;
3434

3535
use std::c_str::ToCStr;
3636
use std::vec;
37-
use syntax::ast_map::{path, path_mod, path_name};
37+
use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
3838
use syntax::ast_util;
3939
use syntax::{ast, ast_map};
4040
use syntax::visit;
@@ -254,7 +254,7 @@ pub fn trans_static_method_callee(bcx: @mut Block,
254254
} else {
255255
let path = csearch::get_item_path(bcx.tcx(), method_id);
256256
match path[path.len()-1] {
257-
path_name(s) => { s }
257+
path_pretty_name(s, _) | path_name(s) => { s }
258258
path_mod(_) => { fail!("path doesn't have a name?") }
259259
}
260260
};

src/librustc/util/ppaux.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,8 @@ impl Repr for ast_map::path_elt {
799799
fn repr(&self, tcx: ctxt) -> ~str {
800800
match *self {
801801
ast_map::path_mod(id) => id.repr(tcx),
802-
ast_map::path_name(id) => id.repr(tcx)
802+
ast_map::path_name(id) => id.repr(tcx),
803+
ast_map::path_pretty_name(id, _) => id.repr(tcx),
803804
}
804805
}
805806
}

src/libsyntax/ast_map.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ use print::pprust;
2222
use visit::{Visitor, fn_kind};
2323
use visit;
2424

25+
use std::hash;
2526
use std::hashmap::HashMap;
2627
use std::vec;
2728

2829
#[deriving(Clone, Eq)]
2930
pub enum path_elt {
3031
path_mod(Ident),
3132
path_name(Ident)
33+
34+
// A pretty name can come from an `impl` block. We attempt to select a
35+
// reasonable name for debuggers to see, but to guarantee uniqueness with
36+
// other paths the hash should also be taken into account during symbol
37+
// generation.
38+
path_pretty_name(Ident, u64),
3239
}
3340

3441
pub type path = ~[path_elt];
@@ -37,8 +44,9 @@ pub fn path_to_str_with_sep(p: &[path_elt], sep: &str, itr: @ident_interner)
3744
-> ~str {
3845
let strs = do p.map |e| {
3946
match *e {
40-
path_mod(s) => itr.get(s.name),
41-
path_name(s) => itr.get(s.name)
47+
path_mod(s) | path_name(s) | path_pretty_name(s, _) => {
48+
itr.get(s.name)
49+
}
4250
}
4351
};
4452
strs.connect(sep)
@@ -58,8 +66,9 @@ pub fn path_to_str(p: &[path_elt], itr: @ident_interner) -> ~str {
5866

5967
pub fn path_elt_to_str(pe: path_elt, itr: @ident_interner) -> ~str {
6068
match pe {
61-
path_mod(s) => itr.get(s.name).to_owned(),
62-
path_name(s) => itr.get(s.name).to_owned()
69+
path_mod(s) | path_name(s) | path_pretty_name(s, _) => {
70+
itr.get(s.name).to_owned()
71+
}
6372
}
6473
}
6574

@@ -195,12 +204,33 @@ impl Visitor<()> for Ctx {
195204
let item_path = @self.path.clone();
196205
self.map.insert(i.id, node_item(i, item_path));
197206
match i.node {
198-
item_impl(_, _, _, ref ms) => {
207+
item_impl(_, ref maybe_trait, ref ty, ref ms) => {
199208
let impl_did = ast_util::local_def(i.id);
200209
for m in ms.iter() {
201210
let extended = { self.extend(i.ident) };
202211
self.map_method(impl_did, extended, *m, false)
203212
}
213+
214+
// Right now the ident on impls is __extensions__ which isn't
215+
// very pretty when debugging, so attempt to select a better
216+
// name to use.
217+
let name = match *maybe_trait {
218+
Some(ref trait_ref) => {
219+
trait_ref.path.segments.last().identifier
220+
}
221+
None => {
222+
match ty.node {
223+
ty_path(ref p, _, _) => {
224+
p.segments.last().identifier
225+
}
226+
// oh well, just give up for now
227+
_ => { i.ident }
228+
}
229+
}
230+
};
231+
232+
let hash = hash::hash_keyed_2(maybe_trait, ty, 0, 0);
233+
self.path.push(path_pretty_name(name, hash));
204234
}
205235
item_enum(ref enum_definition, _) => {
206236
for v in (*enum_definition).variants.iter() {
@@ -267,6 +297,7 @@ impl Visitor<()> for Ctx {
267297
item_mod(_) | item_foreign_mod(_) => {
268298
self.path.push(path_mod(i.ident));
269299
}
300+
item_impl(*) => {} // this was guessed above.
270301
_ => self.path.push(path_name(i.ident))
271302
}
272303
visit::walk_item(self, i, ());

src/test/auxiliary/inner_static.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,53 @@
99
// except according to those terms.
1010

1111
pub struct A<T>;
12+
pub struct B<T>;
13+
14+
pub mod test {
15+
pub struct A<T>;
16+
}
1217

1318
impl<T> A<T> {
1419
pub fn foo(&self) -> int {
15-
static a: int = 5;
20+
static a: int = 1;
1621
return a
1722
}
1823

1924
pub fn bar(&self) -> int {
25+
static a: int = 2;
26+
return a;
27+
}
28+
}
29+
30+
impl<T> B<T> {
31+
pub fn foo(&self) -> int {
2032
static a: int = 3;
33+
return a
34+
}
35+
36+
pub fn bar(&self) -> int {
37+
static a: int = 4;
38+
return a;
39+
}
40+
}
41+
42+
impl<T> test::A<T> {
43+
pub fn foo(&self) -> int {
44+
static a: int = 5;
45+
return a
46+
}
47+
48+
pub fn bar(&self) -> int {
49+
static a: int = 6;
2150
return a;
2251
}
2352
}
2453

2554
pub fn foo() -> int {
2655
let a = A::<()>;
27-
return a.foo() + a.bar();
56+
let b = B::<()>;
57+
let c = test::A::<()>;
58+
return a.foo() + a.bar() +
59+
b.foo() + b.bar() +
60+
c.foo() + c.bar();
2861
}

src/test/run-pass/inner-static.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,9 @@ extern mod inner_static;
1515

1616
pub fn main() {
1717
let a = inner_static::A::<()>;
18-
assert_eq!(a.bar(), 3);
18+
let b = inner_static::B::<()>;
19+
let c = inner_static::test::A::<()>;
20+
assert_eq!(a.bar(), 2);
21+
assert_eq!(b.bar(), 4);
22+
assert_eq!(c.bar(), 6);
1923
}

0 commit comments

Comments
 (0)