Skip to content

Commit 3031720

Browse files
authored
Rollup merge of #66587 - matthewjasper:handle-static-as-const, r=oli-obk
Handle statics in MIR as const pointers This is the first PR towards the goal of removing `PlaceBase::Static`. In this PR: * Statics are lowered to dereferencing a const pointer. * The temporaries holding such pointers are tracked in MIR, for the most part this is only used for diagnostics. There are two exceptions: * The borrow checker has some checks for thread-locals that directly use this data. * Const checking will suppress "cannot dereference raw pointer" diagnostics for pointers to `static mut`/`extern static`. This is to maintain the current behaviour (12 tests fail otherwise). The following are left to future PRs (I think that @spastorino will be working on the first 3): * Applying the same treatments to promoted statics. * Removing `PlaceBase::Static`. * Replacing `PlaceBase` with `Local`. * Moving the ever growing collection of metadata that we have for diagnostics in MIR passes somewhere more appropriate. r? @oli-obk
2 parents c66b508 + bccc59a commit 3031720

39 files changed

+488
-397
lines changed

src/librustc/mir/mod.rs

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::hir::def::{CtorKind, Namespace};
88
use crate::hir::def_id::DefId;
99
use crate::hir;
10-
use crate::mir::interpret::{PanicInfo, Scalar};
10+
use crate::mir::interpret::{GlobalAlloc, PanicInfo, Scalar};
1111
use crate::mir::visit::MirVisitable;
1212
use crate::ty::adjustment::PointerCast;
1313
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@@ -292,7 +292,7 @@ impl<'tcx> Body<'tcx> {
292292
pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
293293
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
294294
let local = Local::new(index);
295-
if self.local_decls[local].is_user_variable.is_some() {
295+
if self.local_decls[local].is_user_variable() {
296296
None
297297
} else {
298298
Some(local)
@@ -305,7 +305,7 @@ impl<'tcx> Body<'tcx> {
305305
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
306306
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
307307
let local = Local::new(index);
308-
if self.local_decls[local].is_user_variable.is_some() {
308+
if self.local_decls[local].is_user_variable() {
309309
Some(local)
310310
} else {
311311
None
@@ -319,7 +319,7 @@ impl<'tcx> Body<'tcx> {
319319
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
320320
let local = Local::new(index);
321321
let decl = &self.local_decls[local];
322-
if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut {
322+
if decl.is_user_variable() && decl.mutability == Mutability::Mut {
323323
Some(local)
324324
} else {
325325
None
@@ -333,7 +333,7 @@ impl<'tcx> Body<'tcx> {
333333
(1..self.local_decls.len()).filter_map(move |index| {
334334
let local = Local::new(index);
335335
let decl = &self.local_decls[local];
336-
if (decl.is_user_variable.is_some() || index < self.arg_count + 1)
336+
if (decl.is_user_variable() || index < self.arg_count + 1)
337337
&& decl.mutability == Mutability::Mut
338338
{
339339
Some(local)
@@ -689,14 +689,8 @@ pub struct LocalDecl<'tcx> {
689689
/// Temporaries and the return place are always mutable.
690690
pub mutability: Mutability,
691691

692-
/// `Some(binding_mode)` if this corresponds to a user-declared local variable.
693-
///
694-
/// This is solely used for local diagnostics when generating
695-
/// warnings/errors when compiling the current crate, and
696-
/// therefore it need not be visible across crates. pnkfelix
697-
/// currently hypothesized we *need* to wrap this in a
698-
/// `ClearCrossCrate` as long as it carries as `HirId`.
699-
pub is_user_variable: Option<ClearCrossCrate<BindingForm<'tcx>>>,
692+
// FIXME(matthewjasper) Don't store in this in `Body`
693+
pub local_info: LocalInfo<'tcx>,
700694

701695
/// `true` if this is an internal local.
702696
///
@@ -721,6 +715,7 @@ pub struct LocalDecl<'tcx> {
721715
/// then it is a temporary created for evaluation of some
722716
/// subexpression of some block's tail expression (with no
723717
/// intervening statement context).
718+
// FIXME(matthewjasper) Don't store in this in `Body`
724719
pub is_block_tail: Option<BlockTailInfo>,
725720

726721
/// The type of this local.
@@ -730,6 +725,7 @@ pub struct LocalDecl<'tcx> {
730725
/// e.g., via `let x: T`, then we carry that type here. The MIR
731726
/// borrow checker needs this information since it can affect
732727
/// region inference.
728+
// FIXME(matthewjasper) Don't store in this in `Body`
733729
pub user_ty: UserTypeProjections,
734730

735731
/// The name of the local, used in debuginfo and pretty-printing.
@@ -824,6 +820,21 @@ pub struct LocalDecl<'tcx> {
824820
pub visibility_scope: SourceScope,
825821
}
826822

823+
/// Extra information about a local that's used for diagnostics.
824+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
825+
pub enum LocalInfo<'tcx> {
826+
/// A user-defined local variable or function parameter
827+
///
828+
/// The `BindingForm` is solely used for local diagnostics when generating
829+
/// warnings/errors when compiling the current crate, and therefore it need
830+
/// not be visible across crates.
831+
User(ClearCrossCrate<BindingForm<'tcx>>),
832+
/// A temporary created that references the static with the given `DefId`.
833+
StaticRef { def_id: DefId, is_thread_local: bool },
834+
/// Any other temporary, the return place, or an anonymous function parameter.
835+
Other,
836+
}
837+
827838
impl<'tcx> LocalDecl<'tcx> {
828839
/// Returns `true` only if local is a binding that can itself be
829840
/// made mutable via the addition of the `mut` keyword, namely
@@ -832,15 +843,17 @@ impl<'tcx> LocalDecl<'tcx> {
832843
/// - `let x = ...`,
833844
/// - or `match ... { C(x) => ... }`
834845
pub fn can_be_made_mutable(&self) -> bool {
835-
match self.is_user_variable {
836-
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
846+
match self.local_info {
847+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
837848
binding_mode: ty::BindingMode::BindByValue(_),
838849
opt_ty_info: _,
839850
opt_match_place: _,
840851
pat_span: _,
841852
}))) => true,
842853

843-
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm))) => true,
854+
LocalInfo::User(
855+
ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm)),
856+
) => true,
844857

845858
_ => false,
846859
}
@@ -850,26 +863,54 @@ impl<'tcx> LocalDecl<'tcx> {
850863
/// `ref mut ident` binding. (Such bindings cannot be made into
851864
/// mutable bindings, but the inverse does not necessarily hold).
852865
pub fn is_nonref_binding(&self) -> bool {
853-
match self.is_user_variable {
854-
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
866+
match self.local_info {
867+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
855868
binding_mode: ty::BindingMode::BindByValue(_),
856869
opt_ty_info: _,
857870
opt_match_place: _,
858871
pat_span: _,
859872
}))) => true,
860873

861-
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
874+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
862875

863876
_ => false,
864877
}
865878
}
866879

880+
/// Returns `true` if this variable is a named variable or function
881+
/// parameter declared by the user.
882+
#[inline]
883+
pub fn is_user_variable(&self) -> bool {
884+
match self.local_info {
885+
LocalInfo::User(_) => true,
886+
_ => false,
887+
}
888+
}
889+
867890
/// Returns `true` if this is a reference to a variable bound in a `match`
868891
/// expression that is used to access said variable for the guard of the
869892
/// match arm.
870893
pub fn is_ref_for_guard(&self) -> bool {
871-
match self.is_user_variable {
872-
Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
894+
match self.local_info {
895+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
896+
_ => false,
897+
}
898+
}
899+
900+
/// Returns `Some` if this is a reference to a static item that is used to
901+
/// access that static
902+
pub fn is_ref_to_static(&self) -> bool {
903+
match self.local_info {
904+
LocalInfo::StaticRef { .. } => true,
905+
_ => false,
906+
}
907+
}
908+
909+
/// Returns `Some` if this is a reference to a static item that is used to
910+
/// access that static
911+
pub fn is_ref_to_thread_local(&self) -> bool {
912+
match self.local_info {
913+
LocalInfo::StaticRef { is_thread_local, .. } => is_thread_local,
873914
_ => false,
874915
}
875916
}
@@ -918,7 +959,7 @@ impl<'tcx> LocalDecl<'tcx> {
918959
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
919960
visibility_scope: OUTERMOST_SOURCE_SCOPE,
920961
internal,
921-
is_user_variable: None,
962+
local_info: LocalInfo::Other,
922963
is_block_tail: None,
923964
}
924965
}
@@ -937,7 +978,7 @@ impl<'tcx> LocalDecl<'tcx> {
937978
internal: false,
938979
is_block_tail: None,
939980
name: None, // FIXME maybe we do want some name here?
940-
is_user_variable: None,
981+
local_info: LocalInfo::Other,
941982
}
942983
}
943984
}
@@ -2341,6 +2382,24 @@ pub struct Constant<'tcx> {
23412382
pub literal: &'tcx ty::Const<'tcx>,
23422383
}
23432384

2385+
impl Constant<'tcx> {
2386+
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
2387+
match self.literal.val.try_to_scalar() {
2388+
Some(Scalar::Ptr(ptr)) => match tcx.alloc_map.lock().get(ptr.alloc_id) {
2389+
Some(GlobalAlloc::Static(def_id)) => Some(def_id),
2390+
Some(_) => None,
2391+
None => {
2392+
tcx.sess.delay_span_bug(
2393+
DUMMY_SP, "MIR cannot contain dangling const pointers",
2394+
);
2395+
None
2396+
},
2397+
},
2398+
_ => None,
2399+
}
2400+
}
2401+
}
2402+
23442403
/// A collection of projections into user types.
23452404
///
23462405
/// They are projections because a binding can occur a part of a

src/librustc/mir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ macro_rules! make_mir_visitor {
691691
source_info,
692692
visibility_scope,
693693
internal: _,
694-
is_user_variable: _,
694+
local_info: _,
695695
is_block_tail: _,
696696
} = local_decl;
697697

src/librustc_codegen_ssa/mir/constant.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,40 @@ use rustc::ty::{self, Ty};
55
use rustc::ty::layout::{self, HasTyCtxt};
66
use syntax::source_map::Span;
77
use crate::traits::*;
8+
use crate::mir::operand::OperandRef;
89

910
use super::FunctionCx;
1011

1112
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13+
pub fn eval_mir_constant_to_operand(
14+
&mut self,
15+
bx: &mut Bx,
16+
constant: &mir::Constant<'tcx>,
17+
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
18+
match constant.literal.val {
19+
ty::ConstKind::Unevaluated(def_id, substs)
20+
if self.cx.tcx().is_static(def_id) => {
21+
assert!(substs.is_empty(), "we don't support generic statics yet");
22+
let static_ = bx.get_static(def_id);
23+
// we treat operands referring to statics as if they were `&STATIC` instead
24+
let ptr_ty = self.cx.tcx().mk_mut_ptr(self.monomorphize(&constant.literal.ty));
25+
let layout = bx.layout_of(ptr_ty);
26+
Ok(OperandRef::from_immediate_or_packed_pair(bx, static_, layout))
27+
}
28+
_ => {
29+
let val = self.eval_mir_constant(constant)?;
30+
Ok(OperandRef::from_const(bx, val))
31+
}
32+
}
33+
}
34+
1235
pub fn eval_mir_constant(
1336
&mut self,
1437
constant: &mir::Constant<'tcx>,
1538
) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
1639
match constant.literal.val {
17-
ty::ConstKind::Unevaluated(def_id, ref substs) => {
18-
let substs = self.monomorphize(substs);
40+
ty::ConstKind::Unevaluated(def_id, substs) => {
41+
let substs = self.monomorphize(&substs);
1942
let instance = ty::Instance::resolve(
2043
self.cx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs,
2144
).unwrap();

src/librustc_codegen_ssa/mir/operand.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,8 +465,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
465465
}
466466

467467
mir::Operand::Constant(ref constant) => {
468-
self.eval_mir_constant(constant)
469-
.map(|c| OperandRef::from_const(bx, c))
468+
self.eval_mir_constant_to_operand(bx, constant)
470469
.unwrap_or_else(|err| {
471470
match err {
472471
// errored or at least linted

src/librustc_mir/borrow_check/borrow_set.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
189189
location: mir::Location,
190190
) {
191191
if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
192-
if borrowed_place.ignore_borrow(
193-
self.tcx, self.body, &self.locals_state_at_exit) {
192+
if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) {
193+
debug!("ignoring_borrow of {:?}", borrowed_place);
194194
return;
195195
}
196196

src/librustc_mir/borrow_check/conflict_errors.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use rustc::hir::def_id::DefId;
33
use rustc::hir::{AsyncGeneratorKind, GeneratorKind};
44
use rustc::mir::{
55
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
6-
FakeReadCause, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef,
7-
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
6+
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
7+
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
88
};
99
use rustc::ty::{self, Ty};
1010
use rustc_data_structures::fx::FxHashSet;
@@ -744,6 +744,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
744744
projection: root_place_projection,
745745
}, borrow_span));
746746

747+
if let PlaceBase::Local(local) = borrow.borrowed_place.base {
748+
if self.body.local_decls[local].is_ref_to_thread_local() {
749+
let err = self.report_thread_local_value_does_not_live_long_enough(
750+
drop_span,
751+
borrow_span,
752+
);
753+
err.buffer(&mut self.errors_buffer);
754+
return;
755+
}
756+
};
757+
747758
if let StorageDeadOrDrop::Destructor(dropped_ty) =
748759
self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
749760
{
@@ -770,9 +781,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
770781
explanation
771782
);
772783
let err = match (place_desc, explanation) {
773-
(Some(_), _) if self.is_place_thread_local(root_place) => {
774-
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
775-
}
776784
// If the outlives constraint comes from inside the closure,
777785
// for example:
778786
//
@@ -1509,19 +1517,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15091517
// place being assigned later.
15101518
let (place_description, assigned_span) = match local_decl {
15111519
Some(LocalDecl {
1512-
is_user_variable: Some(ClearCrossCrate::Clear),
1520+
local_info: LocalInfo::User(ClearCrossCrate::Clear),
15131521
..
15141522
})
15151523
| Some(LocalDecl {
1516-
is_user_variable:
1517-
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1518-
opt_match_place: None,
1519-
..
1520-
}))),
1524+
local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1525+
opt_match_place: None,
1526+
..
1527+
}))),
1528+
..
1529+
})
1530+
| Some(LocalDecl {
1531+
local_info: LocalInfo::StaticRef { .. },
15211532
..
15221533
})
15231534
| Some(LocalDecl {
1524-
is_user_variable: None,
1535+
local_info: LocalInfo::Other,
15251536
..
15261537
})
15271538
| None => (self.describe_place(place.as_ref()), assigned_span),

0 commit comments

Comments
 (0)