1
1
use rustc_data_structures:: base_n;
2
2
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
3
3
use rustc_hir as hir;
4
+ use rustc_hir:: def:: CtorKind ;
4
5
use rustc_hir:: def_id:: { CrateNum , DefId } ;
5
6
use rustc_hir:: definitions:: { DefPathData , DisambiguatedDefPathData } ;
7
+ use rustc_middle:: mir:: interpret:: ConstValue ;
6
8
use rustc_middle:: ty:: layout:: IntegerExt ;
7
9
use rustc_middle:: ty:: print:: { Print , Printer } ;
8
10
use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
@@ -11,6 +13,7 @@ use rustc_target::abi::Integer;
11
13
use rustc_target:: spec:: abi:: Abi ;
12
14
13
15
use std:: fmt:: Write ;
16
+ use std:: iter;
14
17
use std:: ops:: Range ;
15
18
16
19
pub ( super ) fn mangle (
@@ -534,39 +537,153 @@ impl Printer<'tcx> for &mut SymbolMangler<'tcx> {
534
537
}
535
538
536
539
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
+
537
561
if let Some ( & i) = self . consts . get ( & ct) {
538
562
return self . print_backref ( i) ;
539
563
}
540
564
let start = self . out . len ( ) ;
541
565
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 ;
550
576
if val < 0 {
551
- neg = true ;
577
+ self . push ( "n" ) ;
552
578
}
553
- Some ( val. unsigned_abs ( ) )
554
- } )
579
+ bits = val. unsigned_abs ( ) ;
580
+ }
581
+
582
+ let _ = write ! ( self . out, "{:x}_" , bits) ;
555
583
}
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
+
556
684
_ => {
557
685
bug ! ( "symbol_names: unsupported constant of type `{}` ({:?})" , ct. ty, ct) ;
558
686
}
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" ) ;
570
687
}
571
688
572
689
// Only cache consts that do not refer to an enclosing
0 commit comments