Skip to content

Commit

Permalink
Do not recursively visit visit_place
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Jun 8, 2019
1 parent d132f54 commit bafda92
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 119 deletions.
24 changes: 21 additions & 3 deletions src/librustc/mir/visit.rs
Expand Up @@ -160,8 +160,9 @@ macro_rules! make_mir_visitor {

fn visit_projection(&mut self,
place: & $($mutability)? Projection<'tcx>,
context: PlaceContext,
location: Location) {
self.super_projection(place, location);
self.super_projection(place, context, location);
}

fn visit_constant(&mut self,
Expand Down Expand Up @@ -686,8 +687,7 @@ macro_rules! make_mir_visitor {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
};

self.visit_place(& $($mutability)? proj.base, context, location);
self.visit_projection(proj, location);
self.visit_projection(proj, context, location);
}
}
}
Expand All @@ -708,7 +708,25 @@ macro_rules! make_mir_visitor {

fn super_projection(&mut self,
proj: & $($mutability)? Projection<'tcx>,
context: PlaceContext,
location: Location) {
// this is duplicated with `super_place` in preparation for changing `Place` to be
// a struct with a base and a slice of projections. `visit_place` should only ever
// be called for the base place now.
match & $($mutability)? proj.base {
Place::Base(place_base) => {
self.visit_place_base(place_base, context, location);
}
Place::Projection(proj) => {
let context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
};

self.visit_projection(proj, context, location);
}
}
match & $($mutability)? proj.elem {
ProjectionElem::Deref => {
}
Expand Down
28 changes: 18 additions & 10 deletions src/librustc_mir/transform/generator.rs
Expand Up @@ -103,11 +103,11 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location) {
if *place == Place::Base(PlaceBase::Local(self_arg())) {
*place = Place::Projection(Box::new(Projection {
base: place.clone(),
if place.base_local() == Some(self_arg()) {
replace_base(place, Place::Projection(Box::new(Projection {
base: Place::Base(PlaceBase::Local(self_arg())),
elem: ProjectionElem::Deref,
}));
})));
} else {
self.super_place(place, context, location);
}
Expand All @@ -130,17 +130,25 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location) {
if *place == Place::Base(PlaceBase::Local(self_arg())) {
*place = Place::Projection(Box::new(Projection {
base: place.clone(),
if place.base_local() == Some(self_arg()) {
replace_base(place, Place::Projection(Box::new(Projection {
base: Place::Base(PlaceBase::Local(self_arg())),
elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
}));
})));
} else {
self.super_place(place, context, location);
}
}
}

fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
if let Place::Projection(proj) = place {
replace_base(&mut proj.base, new_base);
} else {
*place = new_base;
}
}

fn self_arg() -> Local {
Local::new(1)
}
Expand Down Expand Up @@ -236,10 +244,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location) {
if let Place::Base(PlaceBase::Local(l)) = *place {
if let Some(l) = place.base_local() {
// Replace an Local in the remap with a generator struct access
if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
*place = self.make_field(variant_index, idx, ty);
replace_base(place, self.make_field(variant_index, idx, ty));
}
} else {
self.super_place(place, context, location);
Expand Down
222 changes: 116 additions & 106 deletions src/librustc_mir/transform/qualify_consts.rs
Expand Up @@ -926,125 +926,135 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
/// For functions (constant or not), it also records
/// candidates for promotion in `promotion_candidates`.
impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
fn visit_place(&mut self,
place: &Place<'tcx>,
context: PlaceContext,
location: Location) {
debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
place.iterate(|place_base, place_projections| {
match place_base {
PlaceBase::Local(_) => {}
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
unreachable!()
}
PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
if self.tcx
.get_attrs(*def_id)
.iter()
.any(|attr| attr.check_name(sym::thread_local)) {
if self.mode != Mode::Fn {
span_err!(self.tcx.sess, self.span, E0625,
"thread-local statics cannot be \
accessed at compile-time");
}
return;
fn visit_place_base(
&mut self,
place_base: &PlaceBase<'tcx>,
context: PlaceContext,
location: Location,
) {
self.super_place_base(place_base, context, location);
match place_base {
PlaceBase::Local(_) => {}
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
unreachable!()
}
PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
if self.tcx
.get_attrs(*def_id)
.iter()
.any(|attr| attr.check_name(sym::thread_local)) {
if self.mode != Mode::Fn {
span_err!(self.tcx.sess, self.span, E0625,
"thread-local statics cannot be \
accessed at compile-time");
}
return;
}

// Only allow statics (not consts) to refer to other statics.
if self.mode == Mode::Static || self.mode == Mode::StaticMut {
if self.mode == Mode::Static && context.is_mutating_use() {
// this is not strictly necessary as miri will also bail out
// For interior mutability we can't really catch this statically as that
// goes through raw pointers and intermediate temporaries, so miri has
// to catch this anyway
self.tcx.sess.span_err(
self.span,
"cannot mutate statics in the initializer of another static",
);
}
return;
// Only allow statics (not consts) to refer to other statics.
if self.mode == Mode::Static || self.mode == Mode::StaticMut {
if self.mode == Mode::Static && context.is_mutating_use() {
// this is not strictly necessary as miri will also bail out
// For interior mutability we can't really catch this statically as that
// goes through raw pointers and intermediate temporaries, so miri has
// to catch this anyway
self.tcx.sess.span_err(
self.span,
"cannot mutate statics in the initializer of another static",
);
}
unleash_miri!(self);
return;
}
unleash_miri!(self);

if self.mode != Mode::Fn {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
"{}s cannot refer to statics, use \
a constant instead", self.mode);
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"Static and const variables can refer to other const variables. \
But a const variable cannot refer to a static variable."
);
err.help(
"To fix this, the value can be extracted as a const and then used."
);
}
err.emit()
if self.mode != Mode::Fn {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
"{}s cannot refer to statics, use \
a constant instead", self.mode);
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"Static and const variables can refer to other const variables. \
But a const variable cannot refer to a static variable."
);
err.help(
"To fix this, the value can be extracted as a const and then used."
);
}
err.emit()
}
}
}
}

for proj in place_projections {
match proj.elem {
ProjectionElem::Deref => {
if context.is_mutating_use() {
// `not_const` errors out in const contexts
self.not_const()
}
let base_ty = proj.base.ty(self.mir, self.tcx).ty;
match self.mode {
Mode::Fn => {},
_ => {
if let ty::RawPtr(_) = base_ty.sty {
if !self.tcx.features().const_raw_ptr_deref {
emit_feature_err(
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
self.span, GateIssue::Language,
&format!(
"dereferencing raw pointers in {}s is unstable",
self.mode,
),
);
}
}
fn visit_projection(
&mut self,
proj: &Projection<'tcx>,
context: PlaceContext,
location: Location,
) {
debug!(
"visit_place_projection: proj={:?} context={:?} location={:?}",
proj, context, location,
);
self.super_projection(proj, context, location);
match proj.elem {
ProjectionElem::Deref => {
if context.is_mutating_use() {
// `not_const` errors out in const contexts
self.not_const()
}
let base_ty = proj.base.ty(self.mir, self.tcx).ty;
match self.mode {
Mode::Fn => {},
_ => {
if let ty::RawPtr(_) = base_ty.sty {
if !self.tcx.features().const_raw_ptr_deref {
emit_feature_err(
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
self.span, GateIssue::Language,
&format!(
"dereferencing raw pointers in {}s is unstable",
self.mode,
),
);
}
}
}
}
}

ProjectionElem::ConstantIndex {..} |
ProjectionElem::Subslice {..} |
ProjectionElem::Field(..) |
ProjectionElem::Index(_) => {
let base_ty = proj.base.ty(self.mir, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
if def.is_union() {
match self.mode {
Mode::ConstFn => {
if !self.tcx.features().const_fn_union {
emit_feature_err(
&self.tcx.sess.parse_sess, sym::const_fn_union,
self.span, GateIssue::Language,
"unions in const fn are unstable",
);
}
},

| Mode::Fn
| Mode::Static
| Mode::StaticMut
| Mode::Const
=> {},
ProjectionElem::ConstantIndex {..} |
ProjectionElem::Subslice {..} |
ProjectionElem::Field(..) |
ProjectionElem::Index(_) => {
let base_ty = proj.base.ty(self.mir, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
if def.is_union() {
match self.mode {
Mode::ConstFn => {
if !self.tcx.features().const_fn_union {
emit_feature_err(
&self.tcx.sess.parse_sess, sym::const_fn_union,
self.span, GateIssue::Language,
"unions in const fn are unstable",
);
}
}
}
}
},

ProjectionElem::Downcast(..) => {
self.not_const()
| Mode::Fn
| Mode::Static
| Mode::StaticMut
| Mode::Const
=> {},
}
}
}
}
});

ProjectionElem::Downcast(..) => {
self.not_const()
}
}
}

fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
Expand All @@ -1069,17 +1079,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
// Check nested operands and places.
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
// Special-case reborrows.
let mut is_reborrow = false;
let mut reborrow_place = None;
if let Place::Projection(ref proj) = *place {
if let ProjectionElem::Deref = proj.elem {
let base_ty = proj.base.ty(self.mir, self.tcx).ty;
if let ty::Ref(..) = base_ty.sty {
is_reborrow = true;
reborrow_place = Some(&proj.base);
}
}
}

if is_reborrow {
if let Some(place) = reborrow_place {
let ctx = match kind {
BorrowKind::Shared => PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow,
Expand All @@ -1094,7 +1104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
MutatingUseContext::Borrow,
),
};
self.super_place(place, ctx, location);
self.visit_place(place, ctx, location);
} else {
self.super_rvalue(rvalue, location);
}
Expand Down

0 comments on commit bafda92

Please sign in to comment.