diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 40ebc97a78a6..a7e89e77f340 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>), /// projection out of an lvalue (access a field, deref a pointer, etc) Projection(Box>), } +/// 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 50a80305bee2..638655aee15a 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 7cdbd5cae061..1172172a845c 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 5abfe084f225..ec412d4e9c62 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 af4a4a53905e..c2faf27412c6 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 771a5b7f366a..fb2ef8f60c44 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 2538f32031fd..49e1e3855571 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 000000000000..3e72efada84e --- /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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +struct ArenaSet::Target>(U, &'static V) + where V: 'static + ?Sized; + +static Z: [u8; 4] = [1,2,3,4]; + +fn arena() -> &'static ArenaSet> { + fn __static_ref_initialize() -> ArenaSet> { + ArenaSet(vec![], &Z) + } + unsafe { + use std::sync::{Once, ONCE_INIT}; + fn require_sync(_: &T) { } + unsafe fn __stability() -> &'static ArenaSet> { + use std::mem::transmute; + use std::boxed::Box; + static mut DATA: *const ArenaSet> = 0 as *const ArenaSet>; + + static mut ONCE: Once = ONCE_INIT; + ONCE.call_once(|| { + DATA = transmute + ::>>, *const ArenaSet>> + (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); +}