-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Don't allow static items to have types with destructors #11979
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
4cb3bd5
Remove unused type_is_pod function
flaper87 a22539b
Implement `has_dtor` method in TypeContents
flaper87 c75dd78
Keep track of Enum's with destructors
flaper87 8784d2f
Forbid moves out of static items Closes #10577
flaper87 ee2f001
Forbid certain types for static items
flaper87 49d5d70
Closes #9243 Test case
flaper87 0c7a012
Closes #7364 Test case
flaper87 59a04f5
Immutable static items should be `Freeze` Fixes #12432
flaper87 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// Verifies that the types and values of static items | ||
// are safe. The rules enforced by this module are: | ||
// | ||
// - For each *mutable* static item, it checks that its **type**: | ||
// - doesn't have a destructor | ||
// - doesn't own an owned pointer | ||
// | ||
// - For each *immutable* static item, it checks that its **value**: | ||
// - doesn't own owned, managed pointers | ||
// - doesn't contain a struct literal or a call to an enum variant / struct constructor where | ||
// - the type of the struct/enum is not freeze | ||
// - the type of the struct/enum has a dtor | ||
|
||
use middle::ty; | ||
|
||
use syntax::ast; | ||
use syntax::codemap::Span; | ||
use syntax::visit::Visitor; | ||
use syntax::visit; | ||
use syntax::print::pprust; | ||
|
||
|
||
fn safe_type_for_static_mut(cx: ty::ctxt, e: &ast::Expr) -> Option<~str> { | ||
let node_ty = ty::node_id_to_type(cx, e.id); | ||
let tcontents = ty::type_contents(cx, node_ty); | ||
debug!("safe_type_for_static_mut(dtor={}, managed={}, owned={})", | ||
tcontents.has_dtor(), tcontents.owns_managed(), tcontents.owns_owned()) | ||
|
||
let suffix = if tcontents.has_dtor() { | ||
"destructors" | ||
} else if tcontents.owns_managed() { | ||
"managed pointers" | ||
} else if tcontents.owns_owned() { | ||
"owned pointers" | ||
} else { | ||
return None; | ||
}; | ||
|
||
Some(format!("mutable static items are not allowed to have {}", suffix)) | ||
} | ||
|
||
struct CheckStaticVisitor { | ||
tcx: ty::ctxt, | ||
} | ||
|
||
pub fn check_crate(tcx: ty::ctxt, krate: &ast::Crate) { | ||
visit::walk_crate(&mut CheckStaticVisitor { tcx: tcx }, krate, false) | ||
} | ||
|
||
impl CheckStaticVisitor { | ||
|
||
fn report_error(&self, span: Span, result: Option<~str>) -> bool { | ||
match result { | ||
None => { false } | ||
Some(msg) => { | ||
self.tcx.sess.span_err(span, msg); | ||
true | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl Visitor<bool> for CheckStaticVisitor { | ||
|
||
fn visit_item(&mut self, i: &ast::Item, _is_const: bool) { | ||
debug!("visit_item(item={})", pprust::item_to_str(i)); | ||
match i.node { | ||
ast::ItemStatic(_, mutability, expr) => { | ||
match mutability { | ||
ast::MutImmutable => { | ||
self.visit_expr(expr, true); | ||
} | ||
ast::MutMutable => { | ||
self.report_error(expr.span, safe_type_for_static_mut(self.tcx, expr)); | ||
} | ||
} | ||
} | ||
_ => { visit::walk_item(self, i, false) } | ||
} | ||
} | ||
|
||
/// This method is used to enforce the constraints on | ||
/// immutable static items. It walks through the *value* | ||
/// of the item walking down the expression and evaluating | ||
/// every nested expression. if the expression is not part | ||
/// of a static item, this method does nothing but walking | ||
/// down through it. | ||
fn visit_expr(&mut self, e: &ast::Expr, is_const: bool) { | ||
debug!("visit_expr(expr={})", pprust::expr_to_str(e)); | ||
|
||
if !is_const { | ||
return visit::walk_expr(self, e, is_const); | ||
} | ||
|
||
match e.node { | ||
ast::ExprField(..) | ast::ExprVec(..) | | ||
ast::ExprBlock(..) | ast::ExprTup(..) | | ||
ast::ExprVstore(_, ast::ExprVstoreSlice) => { | ||
visit::walk_expr(self, e, is_const); | ||
} | ||
ast::ExprUnary(ast::UnBox, _) => { | ||
self.tcx.sess.span_err(e.span, | ||
"static items are not allowed to have managed pointers"); | ||
} | ||
ast::ExprBox(..) | | ||
ast::ExprUnary(ast::UnUniq, _) | | ||
ast::ExprVstore(_, ast::ExprVstoreUniq) => { | ||
self.tcx.sess.span_err(e.span, | ||
"static items are not allowed to have owned pointers"); | ||
} | ||
ast::ExprProc(..) => { | ||
self.report_error(e.span, | ||
Some(~"immutable static items must be `Freeze`")); | ||
return; | ||
} | ||
ast::ExprAddrOf(mutability, _) => { | ||
match mutability { | ||
ast::MutMutable => { | ||
self.report_error(e.span, | ||
Some(~"immutable static items must be `Freeze`")); | ||
return; | ||
} | ||
_ => {} | ||
} | ||
} | ||
_ => { | ||
let node_ty = ty::node_id_to_type(self.tcx, e.id); | ||
|
||
match ty::get(node_ty).sty { | ||
ty::ty_struct(did, _) | | ||
ty::ty_enum(did, _) => { | ||
if ty::has_dtor(self.tcx, did) { | ||
self.report_error(e.span, | ||
Some(~"static items are not allowed to have destructors")); | ||
return; | ||
} | ||
if Some(did) == self.tcx.lang_items.no_freeze_bound() { | ||
self.report_error(e.span, | ||
Some(~"immutable static items must be `Freeze`")); | ||
return; | ||
} | ||
} | ||
_ => {} | ||
} | ||
visit::walk_expr(self, e, is_const); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1950,6 +1950,10 @@ impl TypeContents { | |
self.intersects(TC::OwnsManaged) | ||
} | ||
|
||
pub fn owns_owned(&self) -> bool { | ||
self.intersects(TC::OwnsOwned) | ||
} | ||
|
||
pub fn is_freezable(&self, _: ctxt) -> bool { | ||
!self.intersects(TC::Nonfreezable) | ||
} | ||
|
@@ -2012,6 +2016,10 @@ impl TypeContents { | |
pub fn inverse(&self) -> TypeContents { | ||
TypeContents { bits: !self.bits } | ||
} | ||
|
||
pub fn has_dtor(&self) -> bool { | ||
self.intersects(TC::OwnsDtor) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In which case, this accessor is not needed. |
||
} | ||
|
||
impl ops::BitOr<TypeContents,TypeContents> for TypeContents { | ||
|
@@ -2038,6 +2046,10 @@ impl fmt::Show for TypeContents { | |
} | ||
} | ||
|
||
pub fn type_has_dtor(cx: ctxt, t: ty::t) -> bool { | ||
type_contents(cx, t).has_dtor() | ||
} | ||
|
||
pub fn type_is_static(cx: ctxt, t: ty::t) -> bool { | ||
type_contents(cx, t).is_static(cx) | ||
} | ||
|
@@ -2624,61 +2636,6 @@ pub fn type_is_machine(ty: t) -> bool { | |
} | ||
} | ||
|
||
// Whether a type is Plain Old Data -- meaning it does not contain pointers | ||
// that the cycle collector might care about. | ||
pub fn type_is_pod(cx: ctxt, ty: t) -> bool { | ||
let mut result = true; | ||
match get(ty).sty { | ||
// Scalar types | ||
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_float(_) | ty_uint(_) | | ||
ty_ptr(_) | ty_bare_fn(_) => result = true, | ||
// Boxed types | ||
ty_box(_) | ty_uniq(_) | ty_closure(_) | | ||
ty_str(vstore_uniq) | | ||
ty_vec(_, vstore_uniq) | | ||
ty_trait(_, _, _, _, _) | ty_rptr(_,_) => result = false, | ||
// Structural types | ||
ty_enum(did, ref substs) => { | ||
let variants = enum_variants(cx, did); | ||
for variant in (*variants).iter() { | ||
// FIXME(pcwalton): This is an inefficient way to do this. Don't | ||
// synthesize a tuple! | ||
// | ||
// Perform any type parameter substitutions. | ||
let tup_ty = mk_tup(cx, variant.args.clone()); | ||
let tup_ty = subst(cx, substs, tup_ty); | ||
if !type_is_pod(cx, tup_ty) { result = false; } | ||
} | ||
} | ||
ty_tup(ref elts) => { | ||
for elt in elts.iter() { if !type_is_pod(cx, *elt) { result = false; } } | ||
} | ||
ty_str(vstore_fixed(_)) => result = true, | ||
ty_vec(ref mt, vstore_fixed(_)) | ty_unboxed_vec(ref mt) => { | ||
result = type_is_pod(cx, mt.ty); | ||
} | ||
ty_param(_) => result = false, | ||
ty_struct(did, ref substs) => { | ||
let fields = lookup_struct_fields(cx, did); | ||
result = fields.iter().all(|f| { | ||
let fty = ty::lookup_item_type(cx, f.id); | ||
let sty = subst(cx, substs, fty.ty); | ||
type_is_pod(cx, sty) | ||
}); | ||
} | ||
|
||
ty_str(vstore_slice(..)) | ty_vec(_, vstore_slice(..)) => { | ||
result = false; | ||
} | ||
|
||
ty_infer(..) | ty_self(..) | ty_err => { | ||
cx.sess.bug("non concrete type in type_is_pod"); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
pub fn type_is_enum(ty: t) -> bool { | ||
match get(ty).sty { | ||
ty_enum(_, _) => return true, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// Ensure that moves out of static items is forbidden | ||
|
||
use std::kinds::marker; | ||
|
||
struct Foo { | ||
foo: int, | ||
nopod: marker::NoPod | ||
} | ||
|
||
static BAR: Foo = Foo{foo: 5, nopod: marker::NoPod}; | ||
|
||
|
||
fn test(f: Foo) { | ||
let _f = Foo{foo: 4, ..f}; | ||
} | ||
|
||
fn main() { | ||
test(BAR); //~ ERROR cannot move out of static item | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a summary of the rules applied by this file in a doc comment up here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done