Skip to content

Commit 3c3ae1d

Browse files
committed
auto merge of #8875 : alexcrichton/rust/fix-inner-static-library-bug, r=huonw
These commits fix bugs related to identically named statics in functions of implementations in various situations. The commit messages have most of the information about what bugs are being fixed and why. As a bonus, while I was messing around with name mangling, I improved the backtraces we'll get in gdb by removing `__extensions__` for the trait/type being implemented and by adding the method name as well. Yay!
2 parents 2bd628e + 7baff57 commit 3c3ae1d

File tree

13 files changed

+262
-53
lines changed

13 files changed

+262
-53
lines changed

src/librustc/back/link.rs

+76-24
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;
@@ -667,8 +667,7 @@ pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
667667
pub fn symbol_hash(tcx: ty::ctxt,
668668
symbol_hasher: &mut hash::State,
669669
t: ty::t,
670-
link_meta: LinkMeta)
671-
-> @str {
670+
link_meta: LinkMeta) -> @str {
672671
// NB: do *not* use abbrevs here as we want the symbol names
673672
// to be independent of one another in the crate.
674673

@@ -723,7 +722,7 @@ pub fn sanitize(s: &str) -> ~str {
723722
'a' .. 'z'
724723
| 'A' .. 'Z'
725724
| '0' .. '9'
726-
| '_' => result.push_char(c),
725+
| '_' | '.' => result.push_char(c),
727726

728727
_ => {
729728
let mut tstr = ~"";
@@ -744,19 +743,65 @@ pub fn sanitize(s: &str) -> ~str {
744743
return result;
745744
}
746745

747-
pub fn mangle(sess: Session, ss: path) -> ~str {
748-
// Follow C++ namespace-mangling style
746+
pub fn mangle(sess: Session, ss: path,
747+
hash: Option<&str>, vers: Option<&str>) -> ~str {
748+
// Follow C++ namespace-mangling style, see
749+
// http://en.wikipedia.org/wiki/Name_mangling for more info.
750+
//
751+
// It turns out that on OSX you can actually have arbitrary symbols in
752+
// function names (at least when given to LLVM), but this is not possible
753+
// when using unix's linker. Perhaps one day when we just a linker from LLVM
754+
// we won't need to do this name mangling. The problem with name mangling is
755+
// that it seriously limits the available characters. For example we can't
756+
// have things like @T or ~[T] in symbol names when one would theoretically
757+
// want them for things like impls of traits on that type.
758+
//
759+
// To be able to work on all platforms and get *some* reasonable output, we
760+
// use C++ name-mangling.
761+
762+
let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested
763+
764+
let push = |s: &str| {
765+
let sani = sanitize(s);
766+
n.push_str(fmt!("%u%s", sani.len(), sani));
767+
};
749768

750-
let mut n = ~"_ZN"; // Begin name-sequence.
769+
// First, connect each component with <len, name> pairs.
770+
for s in ss.iter() {
771+
match *s {
772+
path_name(s) | path_mod(s) | path_pretty_name(s, _) => {
773+
push(sess.str_of(s))
774+
}
775+
}
776+
}
751777

778+
// next, if any identifiers are "pretty" and need extra information tacked
779+
// on, then use the hash to generate two unique characters. For now
780+
// hopefully 2 characters is enough to avoid collisions.
781+
static EXTRA_CHARS: &'static str =
782+
"abcdefghijklmnopqrstuvwxyz\
783+
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
784+
0123456789";
785+
let mut hash = match hash { Some(s) => s.to_owned(), None => ~"" };
752786
for s in ss.iter() {
753787
match *s {
754-
path_name(s) | path_mod(s) => {
755-
let sani = sanitize(sess.str_of(s));
756-
n.push_str(fmt!("%u%s", sani.len(), sani));
788+
path_pretty_name(_, extra) => {
789+
let hi = (extra >> 32) as u32 as uint;
790+
let lo = extra as u32 as uint;
791+
hash.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char);
792+
hash.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char);
757793
}
794+
_ => {}
758795
}
759796
}
797+
if hash.len() > 0 {
798+
push(hash);
799+
}
800+
match vers {
801+
Some(s) => push(s),
802+
None => {}
803+
}
804+
760805
n.push_char('E'); // End name-sequence.
761806
n
762807
}
@@ -765,10 +810,15 @@ pub fn exported_name(sess: Session,
765810
path: path,
766811
hash: &str,
767812
vers: &str) -> ~str {
768-
mangle(sess,
769-
vec::append_one(
770-
vec::append_one(path, path_name(sess.ident_of(hash))),
771-
path_name(sess.ident_of(vers))))
813+
// The version will get mangled to have a leading '_', but it makes more
814+
// sense to lead with a 'v' b/c this is a version...
815+
let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) {
816+
"v" + vers
817+
} else {
818+
vers.to_owned()
819+
};
820+
821+
mangle(sess, path, Some(hash), Some(vers.as_slice()))
772822
}
773823

774824
pub fn mangle_exported_name(ccx: &mut CrateContext,
@@ -786,31 +836,33 @@ pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
786836
let s = ppaux::ty_to_short_str(ccx.tcx, t);
787837
let hash = get_symbol_hash(ccx, t);
788838
return mangle(ccx.sess,
789-
~[path_name(ccx.sess.ident_of(name)),
790-
path_name(ccx.sess.ident_of(s)),
791-
path_name(ccx.sess.ident_of(hash))]);
839+
~[path_name(ccx.sess.ident_of(name)),
840+
path_name(ccx.sess.ident_of(s))],
841+
Some(hash.as_slice()),
842+
None);
792843
}
793844

794845
pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
795-
t: ty::t,
796-
name: &str) -> ~str {
846+
t: ty::t,
847+
name: &str) -> ~str {
797848
let s = ppaux::ty_to_str(ccx.tcx, t);
798849
let hash = get_symbol_hash(ccx, t);
799850
return mangle(ccx.sess,
800-
~[path_name(ccx.sess.ident_of(s)),
801-
path_name(ccx.sess.ident_of(hash)),
802-
path_name(gensym_name(name))]);
851+
~[path_name(ccx.sess.ident_of(s)),
852+
path_name(gensym_name(name))],
853+
Some(hash.as_slice()),
854+
None);
803855
}
804856

805857
pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
806858
mut path: path,
807859
flav: &str) -> ~str {
808860
path.push(path_name(gensym_name(flav)));
809-
mangle(ccx.sess, path)
861+
mangle(ccx.sess, path, None, None)
810862
}
811863

812864
pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
813-
mangle(ccx.sess, path)
865+
mangle(ccx.sess, path, None, None)
814866
}
815867

816868
pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str {

src/librustc/metadata/common.rs

+4
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

+9
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

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

370379
ebml_w.start_tag(tag_path);

src/librustc/middle/trans/base.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ use std::local_data;
7777
use extra::time;
7878
use extra::sort;
7979
use syntax::ast::Ident;
80-
use syntax::ast_map::{path, path_elt_to_str, path_name};
80+
use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_name};
8181
use syntax::ast_util::{local_def};
8282
use syntax::attr;
8383
use syntax::attr::AttrMetaMethods;
@@ -2627,8 +2627,7 @@ pub fn register_method(ccx: @mut CrateContext,
26272627
let mty = ty::node_id_to_type(ccx.tcx, id);
26282628

26292629
let mut path = (*path).clone();
2630-
path.push(path_name(gensym_name("meth")));
2631-
path.push(path_name(m.ident));
2630+
path.push(path_pretty_name(m.ident, token::gensym("meth") as u64));
26322631

26332632
let sym = exported_name(ccx, path, mty, m.attrs);
26342633

src/librustc/middle/trans/common.rs

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

src/librustc/middle/trans/meth.rs

+2-2
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

+2-1
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
}

0 commit comments

Comments
 (0)