Skip to content

Commit 34ff9aa

Browse files
committed
store the normalized types of statics in MIR Lvalues
The types of statics, like all other items, are stored in the tcx unnormalized. This is necessarily so, because a) Item types other than statics have generics, which can't be normalized. b) Eager normalization causes undesirable on-demand dependencies. Keeping with the principle that MIR lvalues require no normalization in order to interpret, this patch stores the normalized type of the statics in the Lvalue and reads it to get the lvalue type. Fixes #39367.
1 parent ca87082 commit 34ff9aa

File tree

8 files changed

+100
-16
lines changed

8 files changed

+100
-16
lines changed

src/librustc/mir/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,12 +816,20 @@ pub enum Lvalue<'tcx> {
816816
Local(Local),
817817

818818
/// static or static mut variable
819-
Static(DefId),
819+
Static(Box<Static<'tcx>>),
820820

821821
/// projection out of an lvalue (access a field, deref a pointer, etc)
822822
Projection(Box<LvalueProjection<'tcx>>),
823823
}
824824

825+
/// The def-id of a static, along with its normalized type (which is
826+
/// stored to avoid requiring normalization when reading MIR).
827+
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
828+
pub struct Static<'tcx> {
829+
pub def_id: DefId,
830+
pub ty: Ty<'tcx>,
831+
}
832+
825833
/// The `Projection` data structure defines things of the form `B.x`
826834
/// or `*B` or `B[index]`. Note that it is parameterized because it is
827835
/// shared between `Constant` and `Lvalue`. See the aliases
@@ -911,8 +919,8 @@ impl<'tcx> Debug for Lvalue<'tcx> {
911919

912920
match *self {
913921
Local(id) => write!(fmt, "{:?}", id),
914-
Static(def_id) =>
915-
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
922+
Static(box self::Static { def_id, ty }) =>
923+
write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.item_path_str(def_id)), ty),
916924
Projection(ref data) =>
917925
match data.elem {
918926
ProjectionElem::Downcast(ref adt_def, index) =>

src/librustc/mir/tcx.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ impl<'tcx> Lvalue<'tcx> {
125125
match *self {
126126
Lvalue::Local(index) =>
127127
LvalueTy::Ty { ty: mir.local_decls[index].ty },
128-
Lvalue::Static(def_id) =>
129-
LvalueTy::Ty { ty: tcx.item_type(def_id) },
128+
Lvalue::Static(ref data) =>
129+
LvalueTy::Ty { ty: data.ty },
130130
Lvalue::Projection(ref proj) =>
131131
proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
132132
}

src/librustc/mir/visit.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ macro_rules! make_mir_visitor {
154154
self.super_lvalue(lvalue, context, location);
155155
}
156156

157+
fn visit_static(&mut self,
158+
static_: & $($mutability)* Static<'tcx>,
159+
context: LvalueContext<'tcx>,
160+
location: Location) {
161+
self.super_static(static_, context, location);
162+
}
163+
157164
fn visit_projection(&mut self,
158165
lvalue: & $($mutability)* LvalueProjection<'tcx>,
159166
context: LvalueContext<'tcx>,
@@ -559,15 +566,27 @@ macro_rules! make_mir_visitor {
559566
match *lvalue {
560567
Lvalue::Local(_) => {
561568
}
562-
Lvalue::Static(ref $($mutability)* def_id) => {
563-
self.visit_def_id(def_id, location);
569+
Lvalue::Static(ref $($mutability)* static_) => {
570+
self.visit_static(static_, context, location);
564571
}
565572
Lvalue::Projection(ref $($mutability)* proj) => {
566573
self.visit_projection(proj, context, location);
567574
}
568575
}
569576
}
570577

578+
fn super_static(&mut self,
579+
static_: & $($mutability)* Static<'tcx>,
580+
_context: LvalueContext<'tcx>,
581+
location: Location) {
582+
let Static {
583+
ref $($mutability)* def_id,
584+
ref $($mutability)* ty,
585+
} = *static_;
586+
self.visit_def_id(def_id, location);
587+
self.visit_ty(ty);
588+
}
589+
571590
fn super_projection(&mut self,
572591
proj: & $($mutability)* LvalueProjection<'tcx>,
573592
context: LvalueContext<'tcx>,
@@ -837,4 +856,3 @@ impl<'tcx> LvalueContext<'tcx> {
837856
self.is_mutating_use() || self.is_nonmutating_use()
838857
}
839858
}
840-

src/librustc_mir/build/expr/as_lvalue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
8484
block.and(Lvalue::Local(index))
8585
}
8686
ExprKind::StaticRef { id } => {
87-
block.and(Lvalue::Static(id))
87+
block.and(Lvalue::Static(Box::new(Static { def_id: id, ty: expr.ty })))
8888
}
8989

9090
ExprKind::Array { .. } |

src/librustc_mir/transform/type_check.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,18 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
126126
debug!("sanitize_lvalue: {:?}", lvalue);
127127
match *lvalue {
128128
Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
129-
Lvalue::Static(def_id) =>
130-
LvalueTy::Ty { ty: self.tcx().item_type(def_id) },
129+
Lvalue::Static(box Static { def_id, ty: sty }) => {
130+
let sty = self.sanitize_type(lvalue, sty);
131+
let ty = self.tcx().item_type(def_id);
132+
let ty = self.cx.normalize(&ty);
133+
if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) {
134+
span_mirbug!(
135+
self, lvalue, "bad static type ({:?}: {:?}): {:?}",
136+
ty, sty, terr);
137+
}
138+
LvalueTy::Ty { ty: sty }
139+
140+
},
131141
Lvalue::Projection(ref proj) => {
132142
let base_ty = self.sanitize_lvalue(&proj.base, location);
133143
if let LvalueTy::Ty { ty } = base_ty {

src/librustc_trans/mir/constant.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
382382

383383
let lvalue = match *lvalue {
384384
mir::Lvalue::Local(_) => bug!(), // handled above
385-
mir::Lvalue::Static(def_id) => {
385+
mir::Lvalue::Static(box mir::Static { def_id, ty }) => {
386386
ConstLvalue {
387387
base: Base::Static(consts::get_static(self.ccx, def_id)),
388388
llextra: ptr::null_mut(),
389-
ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
389+
ty: self.monomorphize(&ty),
390390
}
391391
}
392392
mir::Lvalue::Projection(ref projection) => {

src/librustc_trans/mir/lvalue.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
304304

305305
let result = match *lvalue {
306306
mir::Lvalue::Local(_) => bug!(), // handled above
307-
mir::Lvalue::Static(def_id) => {
308-
let const_ty = self.monomorphized_lvalue_ty(lvalue);
307+
mir::Lvalue::Static(box mir::Static { def_id, ty }) => {
309308
LvalueRef::new_sized(consts::get_static(ccx, def_id),
310-
LvalueTy::from_ty(const_ty),
309+
LvalueTy::from_ty(self.monomorphize(&ty)),
311310
Alignment::AbiAligned)
312311
},
313312
mir::Lvalue::Projection(box mir::Projection {

src/test/run-pass/issue-39367.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::Deref;
12+
13+
struct ArenaSet<U: Deref, V=<U as Deref>::Target>(U, &'static V)
14+
where V: 'static + ?Sized;
15+
16+
static Z: [u8; 4] = [1,2,3,4];
17+
18+
fn arena() -> &'static ArenaSet<Vec<u8>> {
19+
fn __static_ref_initialize() -> ArenaSet<Vec<u8>> {
20+
ArenaSet(vec![], &Z)
21+
}
22+
unsafe {
23+
use std::sync::{Once, ONCE_INIT};
24+
fn require_sync<T: Sync>(_: &T) { }
25+
unsafe fn __stability() -> &'static ArenaSet<Vec<u8>> {
26+
use std::mem::transmute;
27+
use std::boxed::Box;
28+
static mut DATA: *const ArenaSet<Vec<u8>> = 0 as *const ArenaSet<Vec<u8>>;
29+
30+
static mut ONCE: Once = ONCE_INIT;
31+
ONCE.call_once(|| {
32+
DATA = transmute
33+
::<Box<ArenaSet<Vec<u8>>>, *const ArenaSet<Vec<u8>>>
34+
(Box::new(__static_ref_initialize()));
35+
});
36+
37+
&*DATA
38+
}
39+
let static_ref = __stability();
40+
require_sync(static_ref);
41+
static_ref
42+
}
43+
}
44+
45+
fn main() {
46+
let &ArenaSet(ref u, v) = arena();
47+
assert!(u.is_empty());
48+
assert_eq!(v, Z);
49+
}

0 commit comments

Comments
 (0)