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

get rid of visit_place recursion #61653

Merged
merged 3 commits into from
Jun 9, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 8 additions & 3 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
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,12 @@ macro_rules! make_mir_visitor {

fn super_projection(&mut self,
proj: & $($mutability)? Projection<'tcx>,
context: PlaceContext,
location: Location) {
// this is calling `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 outermost place now.
self.super_place(& $($mutability)? proj.base, context, location);
match & $($mutability)? proj.elem {
ProjectionElem::Deref => {
}
Expand Down
28 changes: 18 additions & 10 deletions src/librustc_mir/transform/generator.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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