about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/mod.rs14
-rw-r--r--src/librustc/mir/tcx.rs4
-rw-r--r--src/librustc/mir/visit.rs24
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs14
-rw-r--r--src/librustc_trans/mir/constant.rs4
-rw-r--r--src/librustc_trans/mir/lvalue.rs5
-rw-r--r--src/test/run-pass/issue-39367.rs49
8 files changed, 100 insertions, 16 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 40ebc97a78a..a7e89e77f34 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -816,12 +816,20 @@ pub enum Lvalue<'tcx> {
     Local(Local),
 
     /// static or static mut variable
-    Static(DefId),
+    Static(Box<Static<'tcx>>),
 
     /// projection out of an lvalue (access a field, deref a pointer, etc)
     Projection(Box<LvalueProjection<'tcx>>),
 }
 
+/// The def-id of a static, along with its normalized type (which is
+/// stored to avoid requiring normalization when reading MIR).
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
+pub struct Static<'tcx> {
+    pub def_id: DefId,
+    pub ty: Ty<'tcx>,
+}
+
 /// The `Projection` data structure defines things of the form `B.x`
 /// or `*B` or `B[index]`. Note that it is parameterized because it is
 /// shared between `Constant` and `Lvalue`. See the aliases
@@ -911,8 +919,8 @@ impl<'tcx> Debug for Lvalue<'tcx> {
 
         match *self {
             Local(id) => write!(fmt, "{:?}", id),
-            Static(def_id) =>
-                write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
+            Static(box self::Static { def_id, ty }) =>
+                write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.item_path_str(def_id)), ty),
             Projection(ref data) =>
                 match data.elem {
                     ProjectionElem::Downcast(ref adt_def, index) =>
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 50a80305bee..638655aee15 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -125,8 +125,8 @@ impl<'tcx> Lvalue<'tcx> {
         match *self {
             Lvalue::Local(index) =>
                 LvalueTy::Ty { ty: mir.local_decls[index].ty },
-            Lvalue::Static(def_id) =>
-                LvalueTy::Ty { ty: tcx.item_type(def_id) },
+            Lvalue::Static(ref data) =>
+                LvalueTy::Ty { ty: data.ty },
             Lvalue::Projection(ref proj) =>
                 proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
         }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 7cdbd5cae06..1172172a845 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -154,6 +154,13 @@ macro_rules! make_mir_visitor {
                 self.super_lvalue(lvalue, context, location);
             }
 
+            fn visit_static(&mut self,
+                            static_: & $($mutability)* Static<'tcx>,
+                            context: LvalueContext<'tcx>,
+                            location: Location) {
+                self.super_static(static_, context, location);
+            }
+
             fn visit_projection(&mut self,
                                 lvalue: & $($mutability)* LvalueProjection<'tcx>,
                                 context: LvalueContext<'tcx>,
@@ -559,8 +566,8 @@ macro_rules! make_mir_visitor {
                 match *lvalue {
                     Lvalue::Local(_) => {
                     }
-                    Lvalue::Static(ref $($mutability)* def_id) => {
-                        self.visit_def_id(def_id, location);
+                    Lvalue::Static(ref $($mutability)* static_) => {
+                        self.visit_static(static_, context, location);
                     }
                     Lvalue::Projection(ref $($mutability)* proj) => {
                         self.visit_projection(proj, context, location);
@@ -568,6 +575,18 @@ macro_rules! make_mir_visitor {
                 }
             }
 
+            fn super_static(&mut self,
+                            static_: & $($mutability)* Static<'tcx>,
+                            _context: LvalueContext<'tcx>,
+                            location: Location) {
+                let Static {
+                    ref $($mutability)* def_id,
+                    ref $($mutability)* ty,
+                } = *static_;
+                self.visit_def_id(def_id, location);
+                self.visit_ty(ty);
+            }
+
             fn super_projection(&mut self,
                                 proj: & $($mutability)* LvalueProjection<'tcx>,
                                 context: LvalueContext<'tcx>,
@@ -837,4 +856,3 @@ impl<'tcx> LvalueContext<'tcx> {
         self.is_mutating_use() || self.is_nonmutating_use()
     }
 }
-
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 5abfe084f22..ec412d4e9c6 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 block.and(Lvalue::Local(index))
             }
             ExprKind::StaticRef { id } => {
-                block.and(Lvalue::Static(id))
+                block.and(Lvalue::Static(Box::new(Static { def_id: id, ty: expr.ty })))
             }
 
             ExprKind::Array { .. } |
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index af4a4a53905..c2faf27412c 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -126,8 +126,18 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         debug!("sanitize_lvalue: {:?}", lvalue);
         match *lvalue {
             Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
-            Lvalue::Static(def_id) =>
-                LvalueTy::Ty { ty: self.tcx().item_type(def_id) },
+            Lvalue::Static(box Static { def_id, ty: sty }) => {
+                let sty = self.sanitize_type(lvalue, sty);
+                let ty = self.tcx().item_type(def_id);
+                let ty = self.cx.normalize(&ty);
+                if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) {
+                    span_mirbug!(
+                        self, lvalue, "bad static type ({:?}: {:?}): {:?}",
+                        ty, sty, terr);
+                }
+                LvalueTy::Ty { ty: sty }
+
+            },
             Lvalue::Projection(ref proj) => {
                 let base_ty = self.sanitize_lvalue(&proj.base, location);
                 if let LvalueTy::Ty { ty } = base_ty {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 771a5b7f366..fb2ef8f60c4 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -382,11 +382,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
         let lvalue = match *lvalue {
             mir::Lvalue::Local(_)  => bug!(), // handled above
-            mir::Lvalue::Static(def_id) => {
+            mir::Lvalue::Static(box mir::Static { def_id, ty }) => {
                 ConstLvalue {
                     base: Base::Static(consts::get_static(self.ccx, def_id)),
                     llextra: ptr::null_mut(),
-                    ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
+                    ty: self.monomorphize(&ty),
                 }
             }
             mir::Lvalue::Projection(ref projection) => {
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index 2538f32031f..49e1e385557 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -304,10 +304,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
         let result = match *lvalue {
             mir::Lvalue::Local(_) => bug!(), // handled above
-            mir::Lvalue::Static(def_id) => {
-                let const_ty = self.monomorphized_lvalue_ty(lvalue);
+            mir::Lvalue::Static(box mir::Static { def_id, ty }) => {
                 LvalueRef::new_sized(consts::get_static(ccx, def_id),
-                                     LvalueTy::from_ty(const_ty),
+                                     LvalueTy::from_ty(self.monomorphize(&ty)),
                                      Alignment::AbiAligned)
             },
             mir::Lvalue::Projection(box mir::Projection {
diff --git a/src/test/run-pass/issue-39367.rs b/src/test/run-pass/issue-39367.rs
new file mode 100644
index 00000000000..3e72efada84
--- /dev/null
+++ b/src/test/run-pass/issue-39367.rs
@@ -0,0 +1,49 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Deref;
+
+struct ArenaSet<U: Deref, V=<U as Deref>::Target>(U, &'static V)
+    where V: 'static + ?Sized;
+
+static Z: [u8; 4] = [1,2,3,4];
+
+fn arena() -> &'static ArenaSet<Vec<u8>> {
+    fn __static_ref_initialize() -> ArenaSet<Vec<u8>> {
+        ArenaSet(vec![], &Z)
+    }
+    unsafe {
+        use std::sync::{Once, ONCE_INIT};
+        fn require_sync<T: Sync>(_: &T) { }
+        unsafe fn __stability() -> &'static ArenaSet<Vec<u8>> {
+            use std::mem::transmute;
+            use std::boxed::Box;
+            static mut DATA: *const ArenaSet<Vec<u8>> = 0 as *const ArenaSet<Vec<u8>>;
+
+            static mut ONCE: Once = ONCE_INIT;
+            ONCE.call_once(|| {
+                DATA = transmute
+                    ::<Box<ArenaSet<Vec<u8>>>, *const ArenaSet<Vec<u8>>>
+                    (Box::new(__static_ref_initialize()));
+            });
+
+            &*DATA
+        }
+        let static_ref = __stability();
+        require_sync(static_ref);
+        static_ref
+    }
+}
+
+fn main() {
+    let &ArenaSet(ref u, v) = arena();
+    assert!(u.is_empty());
+    assert_eq!(v, Z);
+}