about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-08-26 19:15:09 +0000
committerbors <bors@rust-lang.org>2021-08-26 19:15:09 +0000
commitad02dc46badee510bd3a2c093edf80fcaade91b1 (patch)
treec7343646fb600f41303b16ba522bd12022d56546 /compiler
parent4b9f4b221b92193c7e95b1beb502c6eb32c3b613 (diff)
parent24526bbe779b552c3323f3ee1046b534f0888be7 (diff)
downloadrust-ad02dc46badee510bd3a2c093edf80fcaade91b1.tar.gz
rust-ad02dc46badee510bd3a2c093edf80fcaade91b1.zip
Auto merge of #87194 - eddyb:const-value-mangling, r=michaelwoerister,oli-obk
rustc_symbol_mangling: support structural constants and &str in v0.

This PR should unblock #85530 (except for float `const` generics, which AFAIK should've never worked).
(cc `@tmiasko` could the https://github.com/rust-lang/rust/pull/85530#issuecomment-857855379 failures be retried with a quick crater "subset" run of this PR + changing the default to `v0`? Just to make sure I didn't miss anything other than the floats)

The encoding is the one suggested before in e.g. https://github.com/rust-lang/rust/issues/61486#issuecomment-878932102, tho this PR won't by itself finish #61486, before closing that we'd likely want to move to `@oli-obk's` "valtrees" (i.e. #83234 and other associated work).

<hr>

**EDITs**:
1. switched unit/tuple/braced-with-named-fields `<const-fields>` prefixes from `"u"`/`"T"`/`""` to `"U"`/`"T"`/`"S"` to avoid the ambiguity reported by `@tmiasko` in https://github.com/rust-lang/rust/pull/87194#issuecomment-884279921.

2. `rustc-demangle` PR: https://github.com/alexcrichton/rustc-demangle/pull/55

3. RFC amendment PR: https://github.com/rust-lang/rfcs/pull/3161
    * also removed the grammar changes included in that PR, from this description

4. added tests (temporarily using my fork of `rustc-demangle`)

<hr>

r? `@michaelwoerister`
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs17
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml2
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs161
5 files changed, 154 insertions, 29 deletions
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 6187f4000fb..521ce344180 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -15,7 +15,7 @@ measureme = "9.1.0"
 snap = "1"
 tracing = "0.1"
 rustc_middle = { path = "../rustc_middle" }
-rustc-demangle = "0.1.18"
+rustc-demangle = "0.1.21"
 rustc_attr = { path = "../rustc_attr" }
 rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 4befeb1d827..56be2843056 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1220,13 +1220,20 @@ pub trait PrettyPrinter<'tcx>:
                         }
                         p!(")");
                     }
-                    ty::Adt(def, substs) if def.variants.is_empty() => {
-                        p!(print_value_path(def.did, substs));
+                    ty::Adt(def, _) if def.variants.is_empty() => {
+                        self = self.typed_value(
+                            |mut this| {
+                                write!(this, "unreachable()")?;
+                                Ok(this)
+                            },
+                            |this| this.print_type(ty),
+                            ": ",
+                        )?;
                     }
                     ty::Adt(def, substs) => {
-                        let variant_id =
-                            contents.variant.expect("destructed const of adt without variant id");
-                        let variant_def = &def.variants[variant_id];
+                        let variant_idx =
+                            contents.variant.expect("destructed const of adt without variant idx");
+                        let variant_def = &def.variants[variant_idx];
                         p!(print_value_path(variant_def.def_id, substs));
 
                         match variant_def.ctor_kind {
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index aa8fd304527..aebf77a1fd8 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -9,7 +9,7 @@ doctest = false
 [dependencies]
 tracing = "0.1"
 punycode = "0.4.0"
-rustc-demangle = "0.1.18"
+rustc-demangle = "0.1.21"
 
 rustc_span = { path = "../rustc_span" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 850d44eb339..551309f4a8c 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -91,6 +91,7 @@
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(in_band_lifetimes)]
+#![feature(iter_zip)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index c4c1ec8ce4e..80f29aa9c4f 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -1,8 +1,10 @@
 use rustc_data_structures::base_n;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
+use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
@@ -11,6 +13,7 @@ use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 
 use std::fmt::Write;
+use std::iter;
 use std::ops::Range;
 
 pub(super) fn mangle(
@@ -534,39 +537,153 @@ impl Printer<'tcx> for &mut SymbolMangler<'tcx> {
     }
 
     fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+        // We only mangle a typed value if the const can be evaluated.
+        let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
+        match ct.val {
+            ty::ConstKind::Value(_) => {}
+
+            // Placeholders (should be demangled as `_`).
+            // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore
+            // a path), even for it we still need to encode a placeholder, as
+            // the path could refer back to e.g. an `impl` using the constant.
+            ty::ConstKind::Unevaluated(_)
+            | ty::ConstKind::Param(_)
+            | ty::ConstKind::Infer(_)
+            | ty::ConstKind::Bound(..)
+            | ty::ConstKind::Placeholder(_)
+            | ty::ConstKind::Error(_) => {
+                // Never cached (single-character).
+                self.push("p");
+                return Ok(self);
+            }
+        }
+
         if let Some(&i) = self.consts.get(&ct) {
             return self.print_backref(i);
         }
         let start = self.out.len();
 
-        let mut neg = false;
-        let val = match ct.ty.kind() {
-            ty::Uint(_) | ty::Bool | ty::Char => {
-                ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty)
-            }
-            ty::Int(ity) => {
-                ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty).and_then(|b| {
-                    let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(b) as i128;
+        match ct.ty.kind() {
+            ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
+                self = ct.ty.print(self)?;
+
+                let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty);
+
+                // Negative integer values are mangled using `n` as a "sign prefix".
+                if let ty::Int(ity) = ct.ty.kind() {
+                    let val =
+                        Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
                     if val < 0 {
-                        neg = true;
+                        self.push("n");
                     }
-                    Some(val.unsigned_abs())
-                })
+                    bits = val.unsigned_abs();
+                }
+
+                let _ = write!(self.out, "{:x}_", bits);
             }
+
+            // HACK(eddyb) because `ty::Const` only supports sized values (for now),
+            // we can't use `deref_const` + supporting `str`, we have to specially
+            // handle `&str` and include both `&` ("R") and `str` ("e") prefixes.
+            ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => {
+                self.push("R");
+                match ct.val {
+                    ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
+                        // NOTE(eddyb) the following comment was kept from `ty::print::pretty`:
+                        // The `inspect` here is okay since we checked the bounds, and there are no
+                        // relocations (we have an active `str` reference here). We don't use this
+                        // result to affect interpreter execution.
+                        let slice =
+                            data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+                        let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
+
+                        self.push("e");
+                        // FIXME(eddyb) use a specialized hex-encoding loop.
+                        for byte in s.bytes() {
+                            let _ = write!(self.out, "{:02x}", byte);
+                        }
+                        self.push("_");
+                    }
+
+                    _ => {
+                        bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
+                    }
+                }
+            }
+
+            ty::Ref(_, _, mutbl) => {
+                self.push(match mutbl {
+                    hir::Mutability::Not => "R",
+                    hir::Mutability::Mut => "Q",
+                });
+                self = self.tcx.deref_const(ty::ParamEnv::reveal_all().and(ct)).print(self)?;
+            }
+
+            ty::Array(..) | ty::Tuple(..) | ty::Adt(..) => {
+                let contents = self.tcx.destructure_const(ty::ParamEnv::reveal_all().and(ct));
+                let fields = contents.fields.iter().copied();
+
+                let print_field_list = |mut this: Self| {
+                    for field in fields.clone() {
+                        this = field.print(this)?;
+                    }
+                    this.push("E");
+                    Ok(this)
+                };
+
+                match *ct.ty.kind() {
+                    ty::Array(..) => {
+                        self.push("A");
+                        self = print_field_list(self)?;
+                    }
+                    ty::Tuple(..) => {
+                        self.push("T");
+                        self = print_field_list(self)?;
+                    }
+                    ty::Adt(def, substs) => {
+                        let variant_idx =
+                            contents.variant.expect("destructed const of adt without variant idx");
+                        let variant_def = &def.variants[variant_idx];
+
+                        self.push("V");
+                        self = self.print_def_path(variant_def.def_id, substs)?;
+
+                        match variant_def.ctor_kind {
+                            CtorKind::Const => {
+                                self.push("U");
+                            }
+                            CtorKind::Fn => {
+                                self.push("T");
+                                self = print_field_list(self)?;
+                            }
+                            CtorKind::Fictive => {
+                                self.push("S");
+                                for (field_def, field) in iter::zip(&variant_def.fields, fields) {
+                                    // HACK(eddyb) this mimics `path_append`,
+                                    // instead of simply using `field_def.ident`,
+                                    // just to be able to handle disambiguators.
+                                    let disambiguated_field =
+                                        self.tcx.def_key(field_def.did).disambiguated_data;
+                                    let field_name =
+                                        disambiguated_field.data.get_opt_name().map(|s| s.as_str());
+                                    self.push_disambiguator(
+                                        disambiguated_field.disambiguator as u64,
+                                    );
+                                    self.push_ident(&field_name.as_ref().map_or("", |s| &s[..]));
+
+                                    self = field.print(self)?;
+                                }
+                                self.push("E");
+                            }
+                        }
+                    }
+                    _ => unreachable!(),
+                }
+            }
+
             _ => {
                 bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
             }
-        };
-
-        if let Some(bits) = val {
-            // We only print the type if the const can be evaluated.
-            self = ct.ty.print(self)?;
-            let _ = write!(self.out, "{}{:x}_", if neg { "n" } else { "" }, bits);
-        } else {
-            // NOTE(eddyb) despite having the path, we need to
-            // encode a placeholder, as the path could refer
-            // back to e.g. an `impl` using the constant.
-            self.push("p");
         }
 
         // Only cache consts that do not refer to an enclosing