@@ -35,7 +35,7 @@ use std::run;
3535use std:: str;
3636use std:: vec;
3737use 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 } ;
3939use syntax:: attr;
4040use syntax:: attr:: { AttrMetaMethods } ;
4141use syntax:: print:: pprust;
@@ -667,8 +667,7 @@ pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
667667pub 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
774824pub 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
794845pub 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
805857pub 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
812864pub 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
816868pub fn mangle_internal_name_by_seq ( _ccx : & mut CrateContext , flav : & str ) -> ~str {
0 commit comments