Skip to content

Fix bugs in and improve name mangling #8875

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 76 additions & 24 deletions src/librustc/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use std::run;
use std::str;
use std::vec;
use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name};
use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
use syntax::attr;
use syntax::attr::{AttrMetaMethods};
use syntax::print::pprust;
Expand Down Expand Up @@ -663,8 +663,7 @@ pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
pub fn symbol_hash(tcx: ty::ctxt,
symbol_hasher: &mut hash::State,
t: ty::t,
link_meta: LinkMeta)
-> @str {
link_meta: LinkMeta) -> @str {
// NB: do *not* use abbrevs here as we want the symbol names
// to be independent of one another in the crate.

Expand Down Expand Up @@ -719,7 +718,7 @@ pub fn sanitize(s: &str) -> ~str {
'a' .. 'z'
| 'A' .. 'Z'
| '0' .. '9'
| '_' => result.push_char(c),
| '_' | '.' => result.push_char(c),

_ => {
let mut tstr = ~"";
Expand All @@ -740,19 +739,65 @@ pub fn sanitize(s: &str) -> ~str {
return result;
}

pub fn mangle(sess: Session, ss: path) -> ~str {
// Follow C++ namespace-mangling style
pub fn mangle(sess: Session, ss: path,
hash: Option<&str>, vers: Option<&str>) -> ~str {
// Follow C++ namespace-mangling style, see
// http://en.wikipedia.org/wiki/Name_mangling for more info.
//
// It turns out that on OSX you can actually have arbitrary symbols in
// function names (at least when given to LLVM), but this is not possible
// when using unix's linker. Perhaps one day when we just a linker from LLVM
// we won't need to do this name mangling. The problem with name mangling is
// that it seriously limits the available characters. For example we can't
// have things like @T or ~[T] in symbol names when one would theoretically
// want them for things like impls of traits on that type.
//
// To be able to work on all platforms and get *some* reasonable output, we
// use C++ name-mangling.

let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested

let push = |s: &str| {
let sani = sanitize(s);
n.push_str(fmt!("%u%s", sani.len(), sani));
};

let mut n = ~"_ZN"; // Begin name-sequence.
// First, connect each component with <len, name> pairs.
for s in ss.iter() {
match *s {
path_name(s) | path_mod(s) | path_pretty_name(s, _) => {
push(sess.str_of(s))
}
}
}

// next, if any identifiers are "pretty" and need extra information tacked
// on, then use the hash to generate two unique characters. For now
// hopefully 2 characters is enough to avoid collisions.
static EXTRA_CHARS: &'static str =
"abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
0123456789";
let mut hash = match hash { Some(s) => s.to_owned(), None => ~"" };
for s in ss.iter() {
match *s {
path_name(s) | path_mod(s) => {
let sani = sanitize(sess.str_of(s));
n.push_str(fmt!("%u%s", sani.len(), sani));
path_pretty_name(_, extra) => {
let hi = (extra >> 32) as u32 as uint;
let lo = extra as u32 as uint;
hash.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char);
hash.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char);
}
_ => {}
}
}
if hash.len() > 0 {
push(hash);
}
match vers {
Some(s) => push(s),
None => {}
}

n.push_char('E'); // End name-sequence.
n
}
Expand All @@ -761,10 +806,15 @@ pub fn exported_name(sess: Session,
path: path,
hash: &str,
vers: &str) -> ~str {
mangle(sess,
vec::append_one(
vec::append_one(path, path_name(sess.ident_of(hash))),
path_name(sess.ident_of(vers))))
// The version will get mangled to have a leading '_', but it makes more
// sense to lead with a 'v' b/c this is a version...
let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) {
"v" + vers
} else {
vers.to_owned()
};

mangle(sess, path, Some(hash), Some(vers.as_slice()))
}

pub fn mangle_exported_name(ccx: &mut CrateContext,
Expand All @@ -782,31 +832,33 @@ pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
let s = ppaux::ty_to_short_str(ccx.tcx, t);
let hash = get_symbol_hash(ccx, t);
return mangle(ccx.sess,
~[path_name(ccx.sess.ident_of(name)),
path_name(ccx.sess.ident_of(s)),
path_name(ccx.sess.ident_of(hash))]);
~[path_name(ccx.sess.ident_of(name)),
path_name(ccx.sess.ident_of(s))],
Some(hash.as_slice()),
None);
}

pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
t: ty::t,
name: &str) -> ~str {
t: ty::t,
name: &str) -> ~str {
let s = ppaux::ty_to_str(ccx.tcx, t);
let hash = get_symbol_hash(ccx, t);
return mangle(ccx.sess,
~[path_name(ccx.sess.ident_of(s)),
path_name(ccx.sess.ident_of(hash)),
path_name(gensym_name(name))]);
~[path_name(ccx.sess.ident_of(s)),
path_name(gensym_name(name))],
Some(hash.as_slice()),
None);
}

pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
mut path: path,
flav: &str) -> ~str {
path.push(path_name(gensym_name(flav)));
mangle(ccx.sess, path)
mangle(ccx.sess, path, None, None)
}

pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
mangle(ccx.sess, path)
mangle(ccx.sess, path, None, None)
}

pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str {
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ pub static tag_impls_impl: uint = 0x84;
pub static tag_items_data_item_inherent_impl: uint = 0x85;
pub static tag_items_data_item_extension_impl: uint = 0x86;

pub static tag_path_elt_pretty_name: uint = 0x87;
pub static tag_path_elt_pretty_name_ident: uint = 0x88;
pub static tag_path_elt_pretty_name_extra: uint = 0x89;

pub struct LinkMeta {
name: @str,
vers: @str,
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,15 @@ fn item_path(item_doc: ebml::Doc) -> ast_map::path {
} else if tag == tag_path_elt_name {
let str = elt_doc.as_str_slice();
result.push(ast_map::path_name(token::str_to_ident(str)));
} else if tag == tag_path_elt_pretty_name {
let name_doc = reader::get_doc(elt_doc,
tag_path_elt_pretty_name_ident);
let extra_doc = reader::get_doc(elt_doc,
tag_path_elt_pretty_name_extra);
let str = name_doc.as_str_slice();
let extra = reader::doc_as_u64(extra_doc);
result.push(ast_map::path_pretty_name(token::str_to_ident(str),
extra));
} else {
// ignore tag_path_len element
}
Expand Down
21 changes: 15 additions & 6 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,21 @@ fn encode_path(ecx: &EncodeContext,
fn encode_path_elt(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
elt: ast_map::path_elt) {
let (tag, name) = match elt {
ast_map::path_mod(name) => (tag_path_elt_mod, name),
ast_map::path_name(name) => (tag_path_elt_name, name)
};

ebml_w.wr_tagged_str(tag, ecx.tcx.sess.str_of(name));
match elt {
ast_map::path_mod(n) => {
ebml_w.wr_tagged_str(tag_path_elt_mod, ecx.tcx.sess.str_of(n));
}
ast_map::path_name(n) => {
ebml_w.wr_tagged_str(tag_path_elt_name, ecx.tcx.sess.str_of(n));
}
ast_map::path_pretty_name(n, extra) => {
ebml_w.start_tag(tag_path_elt_pretty_name);
ebml_w.wr_tagged_str(tag_path_elt_pretty_name_ident,
ecx.tcx.sess.str_of(n));
ebml_w.wr_tagged_u64(tag_path_elt_pretty_name_extra, extra);
ebml_w.end_tag();
}
}
}

ebml_w.start_tag(tag_path);
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use std::local_data;
use extra::time;
use extra::sort;
use syntax::ast::Ident;
use syntax::ast_map::{path, path_elt_to_str, path_name};
use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_name};
use syntax::ast_util::{local_def};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
Expand Down Expand Up @@ -2646,8 +2646,7 @@ pub fn register_method(ccx: @mut CrateContext,
let mty = ty::node_id_to_type(ccx.tcx, id);

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

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

Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,8 @@ pub fn path_str(sess: session::Session, p: &[path_elt]) -> ~str {
let mut first = true;
for e in p.iter() {
match *e {
ast_map::path_name(s) | ast_map::path_mod(s) => {
ast_map::path_name(s) | ast_map::path_mod(s) |
ast_map::path_pretty_name(s, _) => {
if first {
first = false
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use middle::trans::type_::Type;

use std::c_str::ToCStr;
use std::vec;
use syntax::ast_map::{path, path_mod, path_name};
use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
use syntax::ast_util;
use syntax::{ast, ast_map};
use syntax::visit;
Expand Down Expand Up @@ -254,7 +254,7 @@ pub fn trans_static_method_callee(bcx: @mut Block,
} else {
let path = csearch::get_item_path(bcx.tcx(), method_id);
match path[path.len()-1] {
path_name(s) => { s }
path_pretty_name(s, _) | path_name(s) => { s }
path_mod(_) => { fail!("path doesn't have a name?") }
}
};
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,8 @@ impl Repr for ast_map::path_elt {
fn repr(&self, tcx: ctxt) -> ~str {
match *self {
ast_map::path_mod(id) => id.repr(tcx),
ast_map::path_name(id) => id.repr(tcx)
ast_map::path_name(id) => id.repr(tcx),
ast_map::path_pretty_name(id, _) => id.repr(tcx),
}
}
}
Expand Down
Loading