about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_passes/consts.rs46
-rw-r--r--src/test/compile-fail/issue-44373.rs16
-rw-r--r--src/test/run-pass/issue-44373.rs18
3 files changed, 76 insertions, 4 deletions
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 6f2c448ceb6..547d63fc3d4 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -56,6 +56,7 @@ use std::cmp::Ordering;
 struct CheckCrateVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     in_fn: bool,
+    in_static: bool,
     promotable: bool,
     mut_rvalue_borrows: NodeSet,
     param_env: ty::ParamEnv<'tcx>,
@@ -128,10 +129,16 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         let outer_param_env = self.param_env;
         let outer_identity_substs = self.identity_substs;
 
-        self.in_fn = match MirSource::from_node(self.tcx, item_id) {
-            MirSource::Fn(_) => true,
-            _ => false
+        self.in_fn = false;
+        self.in_static = false;
+
+        match MirSource::from_node(self.tcx, item_id) {
+            MirSource::Fn(_) => self.in_fn = true,
+            MirSource::Static(_, _) => self.in_static = true,
+            _ => {}
         };
+
+
         self.tables = self.tcx.typeck_tables_of(item_def_id);
         self.param_env = self.tcx.param_env(item_def_id);
         self.identity_substs = Substs::identity_for_item(self.tcx, item_def_id);
@@ -327,7 +334,37 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             let def = v.tables.qpath_def(qpath, e.hir_id);
             match def {
                 Def::VariantCtor(..) | Def::StructCtor(..) |
-                Def::Fn(..) | Def::Method(..) => {}
+                Def::Fn(..) | Def::Method(..) =>  {}
+
+                // References to a static that are themselves within a static
+                // are inherently promotable with the exception
+                //  of "#[thread_loca]" statics, which may not
+                // outlive the current function
+                Def::Static(did, _) => {
+
+                    if v.in_static {
+                        let mut thread_local = false;
+
+                        for attr in &v.tcx.get_attrs(did)[..] {
+                            if attr.check_name("thread_local") {
+                                debug!("Reference to Static(id={:?}) is unpromotable \
+                                       due to a #[thread_local] attribute", did);
+                                v.promotable = false;
+                                thread_local = true;
+                                break;
+                            }
+                        }
+
+                        if !thread_local {
+                            debug!("Allowing promotion of reference to Static(id={:?})", did);
+                        }
+                    } else {
+                        debug!("Reference to Static(id={:?}) is unpromotable as it is not \
+                               referenced from a static", did);
+                        v.promotable = false;
+
+                    }
+                }
 
                 Def::Const(did) |
                 Def::AssociatedConst(did) => {
@@ -481,6 +518,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         tcx,
         tables: &ty::TypeckTables::empty(None),
         in_fn: false,
+        in_static: false,
         promotable: false,
         mut_rvalue_borrows: NodeSet(),
         param_env: ty::ParamEnv::empty(Reveal::UserFacing),
diff --git a/src/test/compile-fail/issue-44373.rs b/src/test/compile-fail/issue-44373.rs
new file mode 100644
index 00000000000..d744ad11c5c
--- /dev/null
+++ b/src/test/compile-fail/issue-44373.rs
@@ -0,0 +1,16 @@
+// 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.
+
+
+static FOO: u32 = 50;
+
+fn main() {
+    let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR borrowed value does not live long enough
+}
diff --git a/src/test/run-pass/issue-44373.rs b/src/test/run-pass/issue-44373.rs
new file mode 100644
index 00000000000..06627e2ad93
--- /dev/null
+++ b/src/test/run-pass/issue-44373.rs
@@ -0,0 +1,18 @@
+// 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.
+
+struct Foo(bool);
+
+struct Container(&'static [&'static Foo]);
+
+static FOO: Foo = Foo(true);
+static CONTAINER: Container = Container(&[&FOO]);
+
+fn main() {}