Skip to content

Commit c79244b

Browse files
authored
Rollup merge of rust-lang#60166 - oli-obk:type_name, r=eddyb
Make the `type_name` intrinsic deterministic cc @eddyb for the printing infrastructure cc @Centril for the deterministic (coherent?) output r? @sfackler
2 parents aee7012 + 5b98489 commit c79244b

File tree

10 files changed

+307
-28
lines changed

10 files changed

+307
-28
lines changed

src/librustc/mir/interpret/allocation.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::ops::{Deref, DerefMut};
1212
use rustc_data_structures::sorted_map::SortedMap;
1313
use rustc_macros::HashStable;
1414
use rustc_target::abi::HasDataLayout;
15+
use std::borrow::Cow;
1516

1617
/// Used by `check_bounds` to indicate whether the pointer needs to be just inbounds
1718
/// or also inbounds of a *live* allocation.
@@ -112,10 +113,11 @@ impl AllocationExtra<()> for () { }
112113

113114
impl<Tag, Extra> Allocation<Tag, Extra> {
114115
/// Creates a read-only allocation initialized by the given bytes
115-
pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self {
116-
let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true);
116+
pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align, extra: Extra) -> Self {
117+
let bytes = slice.into().into_owned();
118+
let undef_mask = UndefMask::new(Size::from_bytes(bytes.len() as u64), true);
117119
Self {
118-
bytes: slice.to_owned(),
120+
bytes,
119121
relocations: Relocations::new(),
120122
undef_mask,
121123
align,
@@ -124,7 +126,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
124126
}
125127
}
126128

127-
pub fn from_byte_aligned_bytes(slice: &[u8], extra: Extra) -> Self {
129+
pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, extra: Extra) -> Self {
128130
Allocation::from_bytes(slice, Align::from_bytes(1).unwrap(), extra)
129131
}
130132

src/librustc_codegen_llvm/intrinsic.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
2020
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
2121
use rustc::hir;
2222
use syntax::ast::{self, FloatTy};
23-
use syntax::symbol::LocalInternedString;
2423

2524
use rustc_codegen_ssa::traits::*;
2625

@@ -213,8 +212,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
213212
}
214213
"type_name" => {
215214
let tp_ty = substs.type_at(0);
216-
let ty_name = LocalInternedString::intern(&tp_ty.to_string());
217-
self.const_str_slice(ty_name)
215+
let ty_name = rustc_mir::interpret::type_name(self.tcx, tp_ty);
216+
OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
218217
}
219218
"type_id" => {
220219
self.const_u64(self.tcx.type_id_hash(substs.type_at(0)))

src/librustc_codegen_ssa/mir/operand.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
6868
pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
6969
bx: &mut Bx,
7070
val: &'tcx ty::Const<'tcx>
71-
) -> Result<Self, ErrorHandled> {
71+
) -> Self {
7272
let layout = bx.layout_of(val.ty);
7373

7474
if layout.is_zst() {
75-
return Ok(OperandRef::new_zst(bx, layout));
75+
return OperandRef::new_zst(bx, layout);
7676
}
7777

7878
let val = match val.val {
@@ -110,14 +110,14 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
110110
OperandValue::Pair(a_llval, b_llval)
111111
},
112112
ConstValue::ByRef(ptr, alloc) => {
113-
return Ok(bx.load_operand(bx.from_const_alloc(layout, alloc, ptr.offset)));
113+
return bx.load_operand(bx.from_const_alloc(layout, alloc, ptr.offset));
114114
},
115115
};
116116

117-
Ok(OperandRef {
117+
OperandRef {
118118
val,
119119
layout
120-
})
120+
}
121121
}
122122

123123
/// Asserts that this operand refers to a scalar and returns
@@ -468,7 +468,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
468468
mir::Operand::Constant(ref constant) => {
469469
let ty = self.monomorphize(&constant.ty);
470470
self.eval_mir_constant(constant)
471-
.and_then(|c| OperandRef::from_const(bx, c))
471+
.map(|c| OperandRef::from_const(bx, c))
472472
.unwrap_or_else(|err| {
473473
match err {
474474
// errored or at least linted

src/librustc_codegen_utils/symbol_names.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
427427
mut self,
428428
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
429429
) -> Result<Self::DynExistential, Self::Error> {
430-
let mut first = false;
430+
let mut first = true;
431431
for p in predicates {
432432
if !first {
433433
write!(self, "+")?;

src/librustc_mir/const_eval.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ fn op_to_const<'tcx>(
116116
ptr.offset.bytes(),
117117
),
118118
Scalar::Raw { .. } => (
119-
ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())),
119+
ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(
120+
b"" as &[u8], (),
121+
)),
120122
0,
121123
),
122124
};

src/librustc_mir/interpret/intrinsics.rs

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ use super::{
1414
Machine, PlaceTy, OpTy, InterpretCx,
1515
};
1616

17+
mod type_name;
18+
19+
pub use type_name::*;
1720

1821
fn numeric_intrinsic<'tcx, Tag>(
1922
name: &str,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
use rustc::ty::{
2+
TyCtxt, Ty,
3+
subst::{UnpackedKind, Kind},
4+
print::{Printer, PrettyPrinter, Print},
5+
self,
6+
};
7+
use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
8+
use rustc::hir::def_id::CrateNum;
9+
use std::fmt::Write;
10+
use rustc::mir::interpret::{Allocation, ConstValue};
11+
12+
struct AbsolutePathPrinter<'a, 'tcx> {
13+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
14+
path: String,
15+
}
16+
17+
impl<'tcx> Printer<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
18+
type Error = std::fmt::Error;
19+
20+
type Path = Self;
21+
type Region = Self;
22+
type Type = Self;
23+
type DynExistential = Self;
24+
type Const = Self;
25+
26+
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
27+
self.tcx
28+
}
29+
30+
fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
31+
Ok(self)
32+
}
33+
34+
fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
35+
match ty.sty {
36+
// types without identity
37+
| ty::Bool
38+
| ty::Char
39+
| ty::Int(_)
40+
| ty::Uint(_)
41+
| ty::Float(_)
42+
| ty::Str
43+
| ty::Array(_, _)
44+
| ty::Slice(_)
45+
| ty::RawPtr(_)
46+
| ty::Ref(_, _, _)
47+
| ty::FnPtr(_)
48+
| ty::Never
49+
| ty::Tuple(_)
50+
| ty::Dynamic(_, _)
51+
| ty::Adt(..)
52+
| ty::Foreign(_)
53+
// should be unreachable, but there's no hurt in printing it (and better than ICEing)
54+
| ty::Error
55+
=> self.pretty_print_type(ty),
56+
| ty::Infer(_)
57+
| ty::Bound(_, _)
58+
| ty::Param(_)
59+
| ty::Placeholder(_)
60+
| ty::Projection(_)
61+
| ty::UnnormalizedProjection(_)
62+
| ty::GeneratorWitness(_)
63+
=> bug!(
64+
"{:#?} in `type_name` should not happen because we are always monomorphized",
65+
ty,
66+
),
67+
// types with identity (print the module path instead)
68+
| ty::FnDef(did, substs)
69+
| ty::Opaque(did, substs)
70+
=> self.print_def_path(did, substs),
71+
ty::Closure(did, substs) => self.print_def_path(did, substs.substs),
72+
ty::Generator(did, substs, _) => self.print_def_path(did, substs.substs),
73+
}
74+
}
75+
76+
fn print_const(
77+
self,
78+
_: &'tcx ty::Const<'tcx>,
79+
) -> Result<Self::Const, Self::Error> {
80+
// don't print constants to the user
81+
Ok(self)
82+
}
83+
84+
fn print_dyn_existential(
85+
mut self,
86+
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
87+
) -> Result<Self::DynExistential, Self::Error> {
88+
let mut first = true;
89+
for p in predicates {
90+
if !first {
91+
write!(self, "+")?;
92+
}
93+
first = false;
94+
self = p.print(self)?;
95+
}
96+
Ok(self)
97+
}
98+
99+
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
100+
self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
101+
Ok(self)
102+
}
103+
104+
fn path_qualified(
105+
self,
106+
self_ty: Ty<'tcx>,
107+
trait_ref: Option<ty::TraitRef<'tcx>>,
108+
) -> Result<Self::Path, Self::Error> {
109+
self.pretty_path_qualified(self_ty, trait_ref)
110+
}
111+
112+
fn path_append_impl(
113+
self,
114+
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
115+
_disambiguated_data: &DisambiguatedDefPathData,
116+
self_ty: Ty<'tcx>,
117+
trait_ref: Option<ty::TraitRef<'tcx>>,
118+
) -> Result<Self::Path, Self::Error> {
119+
self.pretty_path_append_impl(
120+
|mut cx| {
121+
cx = print_prefix(cx)?;
122+
123+
cx.path.push_str("::");
124+
125+
Ok(cx)
126+
},
127+
self_ty,
128+
trait_ref,
129+
)
130+
}
131+
132+
fn path_append(
133+
mut self,
134+
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
135+
disambiguated_data: &DisambiguatedDefPathData,
136+
) -> Result<Self::Path, Self::Error> {
137+
self = print_prefix(self)?;
138+
139+
// Skip `::{{constructor}}` on tuple/unit structs.
140+
match disambiguated_data.data {
141+
DefPathData::Ctor => return Ok(self),
142+
_ => {}
143+
}
144+
145+
self.path.push_str("::");
146+
147+
self.path.push_str(&disambiguated_data.data.as_interned_str().as_str());
148+
Ok(self)
149+
}
150+
151+
fn path_generic_args(
152+
mut self,
153+
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
154+
args: &[Kind<'tcx>],
155+
) -> Result<Self::Path, Self::Error> {
156+
self = print_prefix(self)?;
157+
let args = args.iter().cloned().filter(|arg| {
158+
match arg.unpack() {
159+
UnpackedKind::Lifetime(_) => false,
160+
_ => true,
161+
}
162+
});
163+
if args.clone().next().is_some() {
164+
self.generic_delimiters(|cx| cx.comma_sep(args))
165+
} else {
166+
Ok(self)
167+
}
168+
}
169+
}
170+
impl PrettyPrinter<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
171+
fn region_should_not_be_omitted(
172+
&self,
173+
_region: ty::Region<'_>,
174+
) -> bool {
175+
false
176+
}
177+
fn comma_sep<T>(
178+
mut self,
179+
mut elems: impl Iterator<Item = T>,
180+
) -> Result<Self, Self::Error>
181+
where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error>
182+
{
183+
if let Some(first) = elems.next() {
184+
self = first.print(self)?;
185+
for elem in elems {
186+
self.path.push_str(", ");
187+
self = elem.print(self)?;
188+
}
189+
}
190+
Ok(self)
191+
}
192+
193+
fn generic_delimiters(
194+
mut self,
195+
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
196+
) -> Result<Self, Self::Error> {
197+
write!(self, "<")?;
198+
199+
self = f(self)?;
200+
201+
write!(self, ">")?;
202+
203+
Ok(self)
204+
}
205+
}
206+
207+
impl Write for AbsolutePathPrinter<'_, '_> {
208+
fn write_str(&mut self, s: &str) -> std::fmt::Result {
209+
Ok(self.path.push_str(s))
210+
}
211+
}
212+
213+
/// Produces an absolute path representation of the given type. See also the documentation on
214+
/// `std::any::type_name`
215+
pub fn type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
216+
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
217+
let len = path.len();
218+
let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes(), ());
219+
let alloc = tcx.intern_const_alloc(alloc);
220+
tcx.mk_const(ty::Const {
221+
val: ConstValue::Slice {
222+
data: alloc,
223+
start: 0,
224+
end: len,
225+
},
226+
ty: tcx.mk_static_str(),
227+
})
228+
}

src/librustc_mir/interpret/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,5 @@ pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy};
3232
pub use self::visitor::{ValueVisitor, MutValueVisitor};
3333

3434
pub use self::validity::RefTracking;
35+
36+
pub use self::intrinsics::type_name;

0 commit comments

Comments
 (0)