Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mir] Special treatment for dereferencing a borrow to a static definition #74945

Merged
merged 5 commits into from
Aug 1, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions src/librustc_mir/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,9 +502,47 @@ impl<'tcx> Validator<'_, 'tcx> {
fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
match place {
PlaceRef { local, projection: [] } => self.validate_local(local),
PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
PlaceRef { local, projection: [proj_base @ .., elem] } => {
match *elem {
ProjectionElem::Deref | ProjectionElem::Downcast(..) => {
ProjectionElem::Deref => {
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
let mut not_promotable = true;
// This is a special treatment for cases like *&STATIC where STATIC is a
// global static variable.
// This pattern is generated only when global static variables are directly
// accessed and is qualified for promotion safely.
if let TempState::Defined { location, .. } = self.temps[local] {
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
let def_stmt =
self.body[location.block].statements.get(location.statement_index);
if let Some(Statement {
kind:
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(c)))),
..
}) = def_stmt
{
if let Some(did) = c.check_static_ptr(self.tcx) {
if let Some(hir::ConstContext::Static(..)) = self.const_kind {
// The `is_empty` predicate is introduced to exclude the case
// where the projection operations are [ .field, * ].
// The reason is because promotion will be illegal if field
// accesses preceed the dereferencing.
// Discussion can be found at
// https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
// There may be opportunity for generalization, but this needs to be
// accounted for.
if proj_base.is_empty()
&& !self.tcx.is_thread_local_static(did)
{
not_promotable = false;
}
}
}
}
}
if not_promotable {
return Err(Unpromotable);
}
}
ProjectionElem::Downcast(..) => {
return Err(Unpromotable);
}

Expand Down
23 changes: 23 additions & 0 deletions src/test/ui/statics/static-promotion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// check-pass

// Use of global static variables in literal values should be allowed for
// promotion.
// This test is to demonstrate the issue raised in
// https://github.com/rust-lang/rust/issues/70584

// Literal values were previously promoted into local static values when
// other global static variables are used.

struct A<T: 'static>(&'static T);
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
struct B<T: 'static + ?Sized> {
x: &'static T,
}
static C: A<B<B<[u8]>>> = {
A(&B {
x: &B { x: b"hi" as &[u8] },
})
};

fn main() {
assert_eq!(b"hi", C.0.x.x);
}