11use rustc_data_structures:: base_n;
22use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
33use rustc_hir as hir;
4+ use rustc_hir:: def:: CtorKind ;
45use rustc_hir:: def_id:: { CrateNum , DefId } ;
56use rustc_hir:: definitions:: { DefPathData , DisambiguatedDefPathData } ;
7+ use rustc_middle:: mir:: interpret:: ConstValue ;
68use rustc_middle:: ty:: layout:: IntegerExt ;
79use rustc_middle:: ty:: print:: { Print , Printer } ;
810use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
@@ -11,6 +13,7 @@ use rustc_target::abi::Integer;
1113use rustc_target:: spec:: abi:: Abi ;
1214
1315use std:: fmt:: Write ;
16+ use std:: iter;
1417use std:: ops:: Range ;
1518
1619pub ( super ) fn mangle (
@@ -534,39 +537,153 @@ impl Printer<'tcx> for &mut SymbolMangler<'tcx> {
534537 }
535538
536539 fn print_const ( mut self , ct : & ' tcx ty:: Const < ' tcx > ) -> Result < Self :: Const , Self :: Error > {
540+ // We only mangle a typed value if the const can be evaluated.
541+ let ct = ct. eval ( self . tcx , ty:: ParamEnv :: reveal_all ( ) ) ;
542+ match ct. val {
543+ ty:: ConstKind :: Value ( _) => { }
544+
545+ // Placeholders (should be demangled as `_`).
546+ // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore
547+ // a path), even for it we still need to encode a placeholder, as
548+ // the path could refer back to e.g. an `impl` using the constant.
549+ ty:: ConstKind :: Unevaluated ( _)
550+ | ty:: ConstKind :: Param ( _)
551+ | ty:: ConstKind :: Infer ( _)
552+ | ty:: ConstKind :: Bound ( ..)
553+ | ty:: ConstKind :: Placeholder ( _)
554+ | ty:: ConstKind :: Error ( _) => {
555+ // Never cached (single-character).
556+ self . push ( "p" ) ;
557+ return Ok ( self ) ;
558+ }
559+ }
560+
537561 if let Some ( & i) = self . consts . get ( & ct) {
538562 return self . print_backref ( i) ;
539563 }
540564 let start = self . out . len ( ) ;
541565
542- let mut neg = false ;
543- let val = match ct. ty . kind ( ) {
544- ty:: Uint ( _) | ty:: Bool | ty:: Char => {
545- ct. try_eval_bits ( self . tcx , ty:: ParamEnv :: reveal_all ( ) , ct. ty )
546- }
547- ty:: Int ( ity) => {
548- ct. try_eval_bits ( self . tcx , ty:: ParamEnv :: reveal_all ( ) , ct. ty ) . and_then ( |b| {
549- let val = Integer :: from_int_ty ( & self . tcx , * ity) . size ( ) . sign_extend ( b) as i128 ;
566+ match ct. ty . kind ( ) {
567+ ty:: Uint ( _) | ty:: Int ( _) | ty:: Bool | ty:: Char => {
568+ self = ct. ty . print ( self ) ?;
569+
570+ let mut bits = ct. eval_bits ( self . tcx , ty:: ParamEnv :: reveal_all ( ) , ct. ty ) ;
571+
572+ // Negative integer values are mangled using `n` as a "sign prefix".
573+ if let ty:: Int ( ity) = ct. ty . kind ( ) {
574+ let val =
575+ Integer :: from_int_ty ( & self . tcx , * ity) . size ( ) . sign_extend ( bits) as i128 ;
550576 if val < 0 {
551- neg = true ;
577+ self . push ( "n" ) ;
552578 }
553- Some ( val. unsigned_abs ( ) )
554- } )
579+ bits = val. unsigned_abs ( ) ;
580+ }
581+
582+ let _ = write ! ( self . out, "{:x}_" , bits) ;
555583 }
584+
585+ // HACK(eddyb) because `ty::Const` only supports sized values (for now),
586+ // we can't use `deref_const` + supporting `str`, we have to specially
587+ // handle `&str` and include both `&` ("R") and `str` ("e") prefixes.
588+ ty:: Ref ( _, ty, hir:: Mutability :: Not ) if * ty == self . tcx . types . str_ => {
589+ self . push ( "R" ) ;
590+ match ct. val {
591+ ty:: ConstKind :: Value ( ConstValue :: Slice { data, start, end } ) => {
592+ // NOTE(eddyb) the following comment was kept from `ty::print::pretty`:
593+ // The `inspect` here is okay since we checked the bounds, and there are no
594+ // relocations (we have an active `str` reference here). We don't use this
595+ // result to affect interpreter execution.
596+ let slice =
597+ data. inspect_with_uninit_and_ptr_outside_interpreter ( start..end) ;
598+ let s = std:: str:: from_utf8 ( slice) . expect ( "non utf8 str from miri" ) ;
599+
600+ self . push ( "e" ) ;
601+ // FIXME(eddyb) use a specialized hex-encoding loop.
602+ for byte in s. bytes ( ) {
603+ let _ = write ! ( self . out, "{:02x}" , byte) ;
604+ }
605+ self . push ( "_" ) ;
606+ }
607+
608+ _ => {
609+ bug ! ( "symbol_names: unsupported `&str` constant: {:?}" , ct) ;
610+ }
611+ }
612+ }
613+
614+ ty:: Ref ( _, _, mutbl) => {
615+ self . push ( match mutbl {
616+ hir:: Mutability :: Not => "R" ,
617+ hir:: Mutability :: Mut => "Q" ,
618+ } ) ;
619+ self = self . tcx . deref_const ( ty:: ParamEnv :: reveal_all ( ) . and ( ct) ) . print ( self ) ?;
620+ }
621+
622+ ty:: Array ( ..) | ty:: Tuple ( ..) | ty:: Adt ( ..) => {
623+ let contents = self . tcx . destructure_const ( ty:: ParamEnv :: reveal_all ( ) . and ( ct) ) ;
624+ let fields = contents. fields . iter ( ) . copied ( ) ;
625+
626+ let print_field_list = |mut this : Self | {
627+ for field in fields. clone ( ) {
628+ this = field. print ( this) ?;
629+ }
630+ this. push ( "E" ) ;
631+ Ok ( this)
632+ } ;
633+
634+ match * ct. ty . kind ( ) {
635+ ty:: Array ( ..) => {
636+ self . push ( "A" ) ;
637+ self = print_field_list ( self ) ?;
638+ }
639+ ty:: Tuple ( ..) => {
640+ self . push ( "T" ) ;
641+ self = print_field_list ( self ) ?;
642+ }
643+ ty:: Adt ( def, substs) => {
644+ let variant_idx =
645+ contents. variant . expect ( "destructed const of adt without variant idx" ) ;
646+ let variant_def = & def. variants [ variant_idx] ;
647+
648+ self . push ( "V" ) ;
649+ self = self . print_def_path ( variant_def. def_id , substs) ?;
650+
651+ match variant_def. ctor_kind {
652+ CtorKind :: Const => {
653+ self . push ( "U" ) ;
654+ }
655+ CtorKind :: Fn => {
656+ self . push ( "T" ) ;
657+ self = print_field_list ( self ) ?;
658+ }
659+ CtorKind :: Fictive => {
660+ self . push ( "S" ) ;
661+ for ( field_def, field) in iter:: zip ( & variant_def. fields , fields) {
662+ // HACK(eddyb) this mimics `path_append`,
663+ // instead of simply using `field_def.ident`,
664+ // just to be able to handle disambiguators.
665+ let disambiguated_field =
666+ self . tcx . def_key ( field_def. did ) . disambiguated_data ;
667+ let field_name =
668+ disambiguated_field. data . get_opt_name ( ) . map ( |s| s. as_str ( ) ) ;
669+ self . push_disambiguator (
670+ disambiguated_field. disambiguator as u64 ,
671+ ) ;
672+ self . push_ident ( & field_name. as_ref ( ) . map_or ( "" , |s| & s[ ..] ) ) ;
673+
674+ self = field. print ( self ) ?;
675+ }
676+ self . push ( "E" ) ;
677+ }
678+ }
679+ }
680+ _ => unreachable ! ( ) ,
681+ }
682+ }
683+
556684 _ => {
557685 bug ! ( "symbol_names: unsupported constant of type `{}` ({:?})" , ct. ty, ct) ;
558686 }
559- } ;
560-
561- if let Some ( bits) = val {
562- // We only print the type if the const can be evaluated.
563- self = ct. ty . print ( self ) ?;
564- let _ = write ! ( self . out, "{}{:x}_" , if neg { "n" } else { "" } , bits) ;
565- } else {
566- // NOTE(eddyb) despite having the path, we need to
567- // encode a placeholder, as the path could refer
568- // back to e.g. an `impl` using the constant.
569- self . push ( "p" ) ;
570687 }
571688
572689 // Only cache consts that do not refer to an enclosing
0 commit comments