Skip to content

Commit eba374f

Browse files
committed
Auto merge of #44442 - Aaron1011:promote-static-ref, r=eddyb
Fix regression in promotion of rvalues referencing a static This commit makes librustc_passes::consts::CheckCrateVisitor properly mark expressions as promotable if they reference a static, as it's perfectly fine for one static to reference another. It fixes a regression that prevented a temporary rvalue from referencing a static if it was itself declared within a static. Prior to commit b8c05fe90bc, `region::ScopeTree` would only register a 'terminating scope' for function bodies. Thus, while rvalues in a static that referenced a static would be marked unpromotable, the lack of enclosing scope would cause mem_categorization::MemCategorizationContext::cat_rvalue_node to compute a 'temporary scope' of `ReStatic`. Since this had the same effect as explicitly selecting a scope of `ReStatic` due to the rvalue being marked by CheckCrateVisitor as promotable, no issue occurred. However, commit b8c05fe90bc made ScopeTree unconditionally register a 'terminating scope' Since mem_categorization would now compute a non-static 'temporary scope', the aforementioned rvalues would be erroneously marked as living for too short a time. By fixing the behavior of CheckCrateVisitor, this commit avoids changing mem_categorization's behavior, while ensuring that temporary values in statics are still allowed to reference other statics. Fixes issue #44373
2 parents efa3ec6 + fb540e3 commit eba374f

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

src/librustc_passes/consts.rs

+42-4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use std::cmp::Ordering;
5656
struct CheckCrateVisitor<'a, 'tcx: 'a> {
5757
tcx: TyCtxt<'a, 'tcx, 'tcx>,
5858
in_fn: bool,
59+
in_static: bool,
5960
promotable: bool,
6061
mut_rvalue_borrows: NodeSet,
6162
param_env: ty::ParamEnv<'tcx>,
@@ -128,10 +129,16 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
128129
let outer_param_env = self.param_env;
129130
let outer_identity_substs = self.identity_substs;
130131

131-
self.in_fn = match MirSource::from_node(self.tcx, item_id) {
132-
MirSource::Fn(_) => true,
133-
_ => false
132+
self.in_fn = false;
133+
self.in_static = false;
134+
135+
match MirSource::from_node(self.tcx, item_id) {
136+
MirSource::Fn(_) => self.in_fn = true,
137+
MirSource::Static(_, _) => self.in_static = true,
138+
_ => {}
134139
};
140+
141+
135142
self.tables = self.tcx.typeck_tables_of(item_def_id);
136143
self.param_env = self.tcx.param_env(item_def_id);
137144
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
327334
let def = v.tables.qpath_def(qpath, e.hir_id);
328335
match def {
329336
Def::VariantCtor(..) | Def::StructCtor(..) |
330-
Def::Fn(..) | Def::Method(..) => {}
337+
Def::Fn(..) | Def::Method(..) => {}
338+
339+
// References to a static that are themselves within a static
340+
// are inherently promotable with the exception
341+
// of "#[thread_loca]" statics, which may not
342+
// outlive the current function
343+
Def::Static(did, _) => {
344+
345+
if v.in_static {
346+
let mut thread_local = false;
347+
348+
for attr in &v.tcx.get_attrs(did)[..] {
349+
if attr.check_name("thread_local") {
350+
debug!("Reference to Static(id={:?}) is unpromotable \
351+
due to a #[thread_local] attribute", did);
352+
v.promotable = false;
353+
thread_local = true;
354+
break;
355+
}
356+
}
357+
358+
if !thread_local {
359+
debug!("Allowing promotion of reference to Static(id={:?})", did);
360+
}
361+
} else {
362+
debug!("Reference to Static(id={:?}) is unpromotable as it is not \
363+
referenced from a static", did);
364+
v.promotable = false;
365+
366+
}
367+
}
331368

332369
Def::Const(did) |
333370
Def::AssociatedConst(did) => {
@@ -481,6 +518,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
481518
tcx,
482519
tables: &ty::TypeckTables::empty(None),
483520
in_fn: false,
521+
in_static: false,
484522
promotable: false,
485523
mut_rvalue_borrows: NodeSet(),
486524
param_env: ty::ParamEnv::empty(Reveal::UserFacing),

src/test/compile-fail/issue-44373.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
12+
static FOO: u32 = 50;
13+
14+
fn main() {
15+
let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR borrowed value does not live long enough
16+
}

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

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
struct Foo(bool);
12+
13+
struct Container(&'static [&'static Foo]);
14+
15+
static FOO: Foo = Foo(true);
16+
static CONTAINER: Container = Container(&[&FOO]);
17+
18+
fn main() {}

0 commit comments

Comments
 (0)