Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
4d8f995c
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
4d8f995c
编写于
12月 30, 2014
作者:
E
Eduard Burtescu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
rustc: merge check_static into check_const.
上级
8dd1f6a0
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
316 addition
and
410 deletion
+316
-410
src/librustc/lib.rs
src/librustc/lib.rs
+0
-1
src/librustc/middle/check_const.rs
src/librustc/middle/check_const.rs
+299
-50
src/librustc/middle/check_static.rs
src/librustc/middle/check_static.rs
+0
-342
src/librustc_driver/driver.rs
src/librustc_driver/driver.rs
+0
-3
src/test/compile-fail/check-static-immutable-mut-slices.rs
src/test/compile-fail/check-static-immutable-mut-slices.rs
+1
-1
src/test/compile-fail/check-static-values-constraints.rs
src/test/compile-fail/check-static-values-constraints.rs
+8
-7
src/test/compile-fail/issue-17458.rs
src/test/compile-fail/issue-17458.rs
+1
-1
src/test/compile-fail/issue-17718-const-bad-values.rs
src/test/compile-fail/issue-17718-const-bad-values.rs
+2
-2
src/test/compile-fail/issue-18118.rs
src/test/compile-fail/issue-18118.rs
+2
-1
src/test/compile-fail/issue-7364.rs
src/test/compile-fail/issue-7364.rs
+2
-1
src/test/compile-fail/static-mut-not-constant.rs
src/test/compile-fail/static-mut-not-constant.rs
+1
-1
未找到文件。
src/librustc/lib.rs
浏览文件 @
4d8f995c
...
...
@@ -90,7 +90,6 @@ pub mod middle {
pub
mod
check_loop
;
pub
mod
check_match
;
pub
mod
check_rvalues
;
pub
mod
check_static
;
pub
mod
const_eval
;
pub
mod
dataflow
;
pub
mod
dead
;
...
...
src/librustc/middle/check_const.rs
浏览文件 @
4d8f995c
// Copyright 2012-201
3
The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-201
4
The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
...
...
@@ -8,44 +8,117 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Verifies that the types and values of const and 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 has a dtor
//
// Rules Enforced Elsewhere:
// - It's not possible to take the address of a static item with unsafe interior. This is enforced
// by borrowck::gather_loans
use
middle
::
def
::
*
;
use
self
::
Mode
::
*
;
use
middle
::
def
;
use
middle
::
expr_use_visitor
as
euv
;
use
middle
::
infer
;
use
middle
::
mem_categorization
as
mc
;
use
middle
::
traits
;
use
middle
::
ty
;
use
util
::
ppaux
;
use
syntax
::
ast
;
use
syntax
::
codemap
::
Span
;
use
syntax
::
print
::
pprust
;
use
syntax
::
visit
::{
self
,
Visitor
};
#[derive(Copy,
Eq,
PartialEq)]
enum
Mode
{
InConstant
,
InStatic
,
InStaticMut
,
InNothing
,
}
struct
CheckCrateVisitor
<
'a
,
'tcx
:
'a
>
{
tcx
:
&
'a
ty
::
ctxt
<
'tcx
>
,
in_const
:
bool
mode
:
Mode
,
}
impl
<
'a
,
'tcx
>
CheckCrateVisitor
<
'a
,
'tcx
>
{
fn
with_
const
<
F
>
(
&
mut
self
,
in_const
:
bool
,
f
:
F
)
where
fn
with_
mode
<
F
>
(
&
mut
self
,
mode
:
Mode
,
f
:
F
)
where
F
:
FnOnce
(
&
mut
CheckCrateVisitor
<
'a
,
'tcx
>
),
{
let
was_const
=
self
.in_const
;
self
.
in_const
=
in_const
;
let
old
=
self
.mode
;
self
.
mode
=
mode
;
f
(
self
);
self
.
in_const
=
was_const
;
self
.
mode
=
old
;
}
fn
inside_const
<
F
>
(
&
mut
self
,
f
:
F
)
where
F
:
FnOnce
(
&
mut
CheckCrateVisitor
<
'a
,
'tcx
>
),
{
self
.with_const
(
true
,
f
);
fn
msg
(
&
self
)
->
&
'static
str
{
match
self
.mode
{
InConstant
=>
"constant"
,
InStaticMut
|
InStatic
=>
"static"
,
InNothing
=>
unreachable!
(),
}
}
fn
check_static_mut_type
(
&
self
,
e
:
&
ast
::
Expr
)
{
let
node_ty
=
ty
::
node_id_to_type
(
self
.tcx
,
e
.id
);
let
tcontents
=
ty
::
type_contents
(
self
.tcx
,
node_ty
);
let
suffix
=
if
tcontents
.has_dtor
()
{
"destructors"
}
else
if
tcontents
.owns_owned
()
{
"owned pointers"
}
else
{
return
};
self
.tcx.sess
.span_err
(
e
.span
,
&
format!
(
"mutable statics are not allowed
\
to have {}"
,
suffix
)[]);
}
fn
check_static_type
(
&
self
,
e
:
&
ast
::
Expr
)
{
let
ty
=
ty
::
node_id_to_type
(
self
.tcx
,
e
.id
);
let
infcx
=
infer
::
new_infer_ctxt
(
self
.tcx
);
let
mut
fulfill_cx
=
traits
::
FulfillmentContext
::
new
();
let
cause
=
traits
::
ObligationCause
::
new
(
e
.span
,
e
.id
,
traits
::
SharedStatic
);
fulfill_cx
.register_builtin_bound
(
&
infcx
,
ty
,
ty
::
BoundSync
,
cause
);
let
env
=
ty
::
empty_parameter_environment
(
self
.tcx
);
match
fulfill_cx
.select_all_or_error
(
&
infcx
,
&
env
)
{
Ok
(())
=>
{
},
Err
(
ref
errors
)
=>
{
traits
::
report_fulfillment_errors
(
&
infcx
,
errors
);
}
}
}
}
impl
<
'a
,
'tcx
,
'v
>
Visitor
<
'v
>
for
CheckCrateVisitor
<
'a
,
'tcx
>
{
fn
visit_item
(
&
mut
self
,
i
:
&
ast
::
Item
)
{
debug!
(
"visit_item(item={})"
,
pprust
::
item_to_string
(
i
));
match
i
.node
{
ast
::
ItemStatic
(
_
,
_
,
ref
ex
)
|
ast
::
ItemConst
(
_
,
ref
ex
)
=>
{
self
.inside_const
(|
v
|
v
.visit_expr
(
&**
ex
));
ast
::
ItemStatic
(
_
,
ast
::
MutImmutable
,
ref
expr
)
=>
{
self
.check_static_type
(
&**
expr
);
self
.with_mode
(
InStatic
,
|
v
|
v
.visit_expr
(
&**
expr
));
}
ast
::
ItemStatic
(
_
,
ast
::
MutMutable
,
ref
expr
)
=>
{
self
.check_static_mut_type
(
&**
expr
);
self
.with_mode
(
InStaticMut
,
|
v
|
v
.visit_expr
(
&**
expr
));
}
ast
::
ItemConst
(
_
,
ref
expr
)
=>
{
self
.with_mode
(
InConstant
,
|
v
|
v
.visit_expr
(
&**
expr
));
}
ast
::
ItemEnum
(
ref
enum_definition
,
_
)
=>
{
self
.
inside_const
(
|
v
|
{
self
.
with_mode
(
InConstant
,
|
v
|
{
for
var
in
&
enum_definition
.variants
{
if
let
Some
(
ref
ex
)
=
var
.node.disr_expr
{
v
.visit_expr
(
&**
ex
);
...
...
@@ -53,46 +126,60 @@ fn visit_item(&mut self, i: &ast::Item) {
}
});
}
_
=>
self
.with_const
(
false
,
|
v
|
visit
::
walk_item
(
v
,
i
))
_
=>
{
self
.with_mode
(
InNothing
,
|
v
|
visit
::
walk_item
(
v
,
i
));
}
}
}
fn
visit_pat
(
&
mut
self
,
p
:
&
ast
::
Pat
)
{
let
is_const
=
match
p
.node
{
ast
::
PatLit
(
_
)
|
ast
::
PatRange
(
..
)
=>
true
,
_
=>
false
let
mode
=
match
p
.node
{
ast
::
PatLit
(
_
)
|
ast
::
PatRange
(
..
)
=>
InConstant
,
_
=>
InNothing
};
self
.with_
const
(
is_const
,
|
v
|
visit
::
walk_pat
(
v
,
p
))
self
.with_
mode
(
mode
,
|
v
|
visit
::
walk_pat
(
v
,
p
))
}
fn
visit_expr
(
&
mut
self
,
ex
:
&
ast
::
Expr
)
{
if
self
.
in_const
{
if
self
.
mode
!=
InNothing
{
check_expr
(
self
,
ex
);
}
visit
::
walk_expr
(
self
,
ex
);
}
}
pub
fn
check_crate
(
tcx
:
&
ty
::
ctxt
)
{
visit
::
walk_crate
(
&
mut
CheckCrateVisitor
{
tcx
:
tcx
,
in_const
:
false
},
tcx
.map
.krate
());
tcx
.sess
.abort_if_errors
();
}
/// This function is used to enforce the constraints on
/// const/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 const/static item, this function does nothing but
/// walking down through it.
fn
check_expr
(
v
:
&
mut
CheckCrateVisitor
,
e
:
&
ast
::
Expr
)
{
let
node_ty
=
ty
::
node_id_to_type
(
v
.tcx
,
e
.id
);
match
node_ty
.sty
{
ty
::
ty_struct
(
did
,
_
)
|
ty
::
ty_enum
(
did
,
_
)
if
ty
::
has_dtor
(
v
.tcx
,
did
)
=>
{
v
.tcx.sess
.span_err
(
e
.span
,
&
format!
(
"{}s are not allowed to have destructors"
,
v
.msg
())[])
}
_
=>
{}
}
match
e
.node
{
ast
::
Expr
Unary
(
ast
::
UnDeref
,
_
)
=>
{}
ast
::
Expr
Box
(
..
)
|
ast
::
ExprUnary
(
ast
::
UnUniq
,
_
)
=>
{
span_err!
(
v
.tcx.sess
,
e
.span
,
E0010
,
"
cannot do allocations in constant expressions"
);
"
allocations are not allowed in {}s"
,
v
.msg
()
);
}
ast
::
ExprBinary
(
..
)
|
ast
::
ExprUnary
(
..
)
=>
{
let
method_call
=
ty
::
MethodCall
::
expr
(
e
.id
);
if
v
.tcx.method_map
.borrow
()
.contains_key
(
&
method_call
)
{
span_err!
(
v
.tcx.sess
,
e
.span
,
E0011
,
"user-defined operators are not allowed in constant
\
expressions"
);
"user-defined operators are not allowed in {}s"
,
v
.msg
());
}
}
ast
::
ExprLit
(
_
)
=>
{}
ast
::
ExprCast
(
ref
from
,
_
)
=>
{
let
toty
=
ty
::
expr_ty
(
v
.tcx
,
e
);
let
fromty
=
ty
::
expr_ty
(
v
.tcx
,
&**
from
);
...
...
@@ -102,20 +189,24 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
(
ty
::
type_is_bare_fn
(
toty
)
&&
ty
::
type_is_bare_fn_item
(
fromty
));
if
!
is_legal_cast
{
span_err!
(
v
.tcx.sess
,
e
.span
,
E0012
,
"can not cast to `{}` in
a constant expression
"
,
ppaux
::
ty_to_string
(
v
.tcx
,
toty
));
"can not cast to `{}` in
{}s
"
,
ppaux
::
ty_to_string
(
v
.tcx
,
toty
)
,
v
.msg
()
);
}
if
ty
::
type_is_unsafe_ptr
(
fromty
)
&&
ty
::
type_is_numeric
(
toty
)
{
span_err!
(
v
.tcx.sess
,
e
.span
,
E0018
,
"can not cast a pointer to an integer in a constant
\
expression"
);
"can not cast a pointer to an integer in {}s"
,
v
.msg
());
}
}
ast
::
ExprPath
(
_
)
|
ast
::
ExprQPath
(
_
)
=>
{
match
v
.tcx.def_map
.borrow
()[
e
.id
]
{
DefStatic
(
..
)
|
DefConst
(
..
)
|
DefFn
(
..
)
|
DefStaticMethod
(
..
)
|
DefMethod
(
..
)
|
DefStruct
(
_
)
|
DefVariant
(
_
,
_
,
_
)
=>
{}
def
::
DefStatic
(
..
)
if
v
.mode
==
InConstant
=>
{
span_err!
(
v
.tcx.sess
,
e
.span
,
E0013
,
"constants cannot refer to other statics,
\
insert an intermediate constant instead"
);
}
def
::
DefStatic
(
..
)
|
def
::
DefConst
(
..
)
|
def
::
DefFn
(
..
)
|
def
::
DefStaticMethod
(
..
)
|
def
::
DefMethod
(
..
)
|
def
::
DefStruct
(
_
)
|
def
::
DefVariant
(
_
,
_
,
_
)
=>
{}
def
=>
{
debug!
(
"(checking const) found bad def: {:?}"
,
def
);
...
...
@@ -127,7 +218,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
}
ast
::
ExprCall
(
ref
callee
,
_
)
=>
{
match
v
.tcx.def_map
.borrow
()[
callee
.id
]
{
DefStruct
(
..
)
|
DefVariant
(
..
)
=>
{}
// OK.
def
::
DefStruct
(
..
)
|
def
::
DefVariant
(
..
)
=>
{}
// OK.
_
=>
{
span_err!
(
v
.tcx.sess
,
e
.span
,
E0015
,
"function calls in constants are limited to
\
...
...
@@ -160,6 +251,17 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
}
}
}
ast
::
ExprAddrOf
(
ast
::
MutMutable
,
ref
inner
)
=>
{
match
inner
.node
{
// Mutable slices are allowed. Only in `static mut`.
ast
::
ExprVec
(
_
)
if
v
.mode
==
InStaticMut
=>
{}
_
=>
span_err!
(
v
.tcx.sess
,
e
.span
,
E0017
,
"references in {}s may only refer
\
to immutable values"
,
v
.msg
())
}
}
ast
::
ExprLit
(
_
)
|
ast
::
ExprVec
(
_
)
|
ast
::
ExprAddrOf
(
ast
::
MutImmutable
,
_
)
|
ast
::
ExprParen
(
..
)
|
...
...
@@ -170,18 +272,165 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
ast
::
ExprRepeat
(
..
)
|
ast
::
ExprStruct
(
..
)
=>
{}
ast
::
ExprAddrOf
(
_
,
ref
inner
)
=>
{
match
inner
.node
{
// Mutable slices are allowed.
ast
::
ExprVec
(
_
)
=>
{}
_
=>
span_err!
(
v
.tcx.sess
,
e
.span
,
E0017
,
"references in constants may only refer
\
to immutable values"
)
// Conditional control flow (possible to implement).
ast
::
ExprMatch
(
..
)
|
ast
::
ExprIf
(
..
)
|
ast
::
ExprIfLet
(
..
)
|
}
// Loops (not very meaningful in constants).
ast
::
ExprWhile
(
..
)
|
ast
::
ExprWhileLet
(
..
)
|
ast
::
ExprForLoop
(
..
)
|
ast
::
ExprLoop
(
..
)
|
// More control flow (also not very meaningful).
ast
::
ExprBreak
(
_
)
|
ast
::
ExprAgain
(
_
)
|
ast
::
ExprRet
(
_
)
|
// Miscellaneous expressions that could be implemented.
ast
::
ExprClosure
(
..
)
|
ast
::
ExprRange
(
..
)
|
// Various other expressions.
ast
::
ExprMethodCall
(
..
)
|
ast
::
ExprAssign
(
..
)
|
ast
::
ExprAssignOp
(
..
)
|
ast
::
ExprInlineAsm
(
_
)
|
ast
::
ExprMac
(
_
)
=>
{
span_err!
(
v
.tcx.sess
,
e
.span
,
E0019
,
"{} contains unimplemented expression type"
,
v
.msg
());
}
}
}
_
=>
span_err!
(
v
.tcx.sess
,
e
.span
,
E0019
,
"constant contains unimplemented expression type"
)
struct
GlobalVisitor
<
'a
,
'b
,
'tcx
:
'a
+
'b
>
(
euv
::
ExprUseVisitor
<
'a
,
'b
,
'tcx
,
ty
::
ParameterEnvironment
<
'b
,
'tcx
>>
);
struct
GlobalChecker
<
'a
,
'tcx
:
'a
>
{
tcx
:
&
'a
ty
::
ctxt
<
'tcx
>
}
pub
fn
check_crate
(
tcx
:
&
ty
::
ctxt
)
{
let
param_env
=
ty
::
empty_parameter_environment
(
tcx
);
let
mut
checker
=
GlobalChecker
{
tcx
:
tcx
};
let
visitor
=
euv
::
ExprUseVisitor
::
new
(
&
mut
checker
,
&
param_env
);
visit
::
walk_crate
(
&
mut
GlobalVisitor
(
visitor
),
tcx
.map
.krate
());
visit
::
walk_crate
(
&
mut
CheckCrateVisitor
{
tcx
:
tcx
,
mode
:
InNothing
,
},
tcx
.map
.krate
());
tcx
.sess
.abort_if_errors
();
}
impl
<
'a
,
'b
,
't
,
'v
>
Visitor
<
'v
>
for
GlobalVisitor
<
'a
,
'b
,
't
>
{
fn
visit_item
(
&
mut
self
,
item
:
&
ast
::
Item
)
{
match
item
.node
{
ast
::
ItemConst
(
_
,
ref
e
)
|
ast
::
ItemStatic
(
_
,
_
,
ref
e
)
=>
{
let
GlobalVisitor
(
ref
mut
v
)
=
*
self
;
v
.consume_expr
(
&**
e
);
}
_
=>
{}
}
visit
::
walk_item
(
self
,
item
);
}
}
impl
<
'a
,
'tcx
>
euv
::
Delegate
<
'tcx
>
for
GlobalChecker
<
'a
,
'tcx
>
{
fn
consume
(
&
mut
self
,
_
consume_id
:
ast
::
NodeId
,
consume_span
:
Span
,
cmt
:
mc
::
cmt
,
_
mode
:
euv
::
ConsumeMode
)
{
let
mut
cur
=
&
cmt
;
loop
{
match
cur
.cat
{
mc
::
cat_static_item
=>
{
// statics cannot be consumed by value at any time, that would imply
// that they're an initializer (what a const is for) or kept in sync
// over time (not feasible), so deny it outright.
self
.tcx.sess
.span_err
(
consume_span
,
"cannot refer to other statics by value, use the
\
address-of operator or a constant instead"
);
break
;
}
mc
::
cat_deref
(
ref
cmt
,
_
,
_
)
|
mc
::
cat_downcast
(
ref
cmt
,
_
)
|
mc
::
cat_interior
(
ref
cmt
,
_
)
=>
cur
=
cmt
,
mc
::
cat_rvalue
(
..
)
|
mc
::
cat_upvar
(
..
)
|
mc
::
cat_local
(
..
)
=>
break
}
}
}
fn
borrow
(
&
mut
self
,
_
borrow_id
:
ast
::
NodeId
,
borrow_span
:
Span
,
cmt
:
mc
::
cmt
<
'tcx
>
,
_
loan_region
:
ty
::
Region
,
_
bk
:
ty
::
BorrowKind
,
_
loan_cause
:
euv
::
LoanCause
)
{
let
mut
cur
=
&
cmt
;
let
mut
is_interior
=
false
;
loop
{
match
cur
.cat
{
mc
::
cat_rvalue
(
..
)
=>
{
// constants cannot be borrowed if they contain interior mutability as
// it means that our "silent insertion of statics" could change
// initializer values (very bad).
if
ty
::
type_contents
(
self
.tcx
,
cur
.ty
)
.interior_unsafe
()
{
self
.tcx.sess
.span_err
(
borrow_span
,
"cannot borrow a constant which contains
\
interior mutability, create a static instead"
);
}
break
;
}
mc
::
cat_static_item
=>
{
if
is_interior
{
// Borrowed statics can specifically *only* have their address taken,
// not any number of other borrows such as borrowing fields, reading
// elements of an array, etc.
self
.tcx.sess
.span_err
(
borrow_span
,
"cannot refer to the interior of another
\
static, use a constant instead"
);
}
break
;
}
mc
::
cat_deref
(
ref
cmt
,
_
,
_
)
|
mc
::
cat_downcast
(
ref
cmt
,
_
)
|
mc
::
cat_interior
(
ref
cmt
,
_
)
=>
{
is_interior
=
true
;
cur
=
cmt
;
}
mc
::
cat_upvar
(
..
)
|
mc
::
cat_local
(
..
)
=>
break
}
}
}
fn
decl_without_init
(
&
mut
self
,
_
id
:
ast
::
NodeId
,
_
span
:
Span
)
{}
fn
mutate
(
&
mut
self
,
_
assignment_id
:
ast
::
NodeId
,
_
assignment_span
:
Span
,
_
assignee_cmt
:
mc
::
cmt
,
_
mode
:
euv
::
MutateMode
)
{}
fn
matched_pat
(
&
mut
self
,
_
:
&
ast
::
Pat
,
_
:
mc
::
cmt
,
_
:
euv
::
MatchMode
)
{}
fn
consume_pat
(
&
mut
self
,
_
consume_pat
:
&
ast
::
Pat
,
_
cmt
:
mc
::
cmt
,
_
mode
:
euv
::
ConsumeMode
)
{}
}
\ No newline at end of file
src/librustc/middle/check_static.rs
已删除
100644 → 0
浏览文件 @
8dd1f6a0
// 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 has a dtor
//
// Rules Enforced Elsewhere:
// - It's not possible to take the address of a static item with unsafe interior. This is enforced
// by borrowck::gather_loans
use
self
::
Mode
::
*
;
use
middle
::
ty
;
use
middle
::
def
;
use
middle
::
infer
;
use
middle
::
traits
;
use
middle
::
mem_categorization
as
mc
;
use
middle
::
expr_use_visitor
as
euv
;
use
util
::
nodemap
::
NodeSet
;
use
syntax
::
ast
;
use
syntax
::
print
::
pprust
;
use
syntax
::
visit
::
Visitor
;
use
syntax
::
codemap
::
Span
;
use
syntax
::
visit
;
#[derive(Copy,
Eq,
PartialEq)]
enum
Mode
{
InConstant
,
InStatic
,
InStaticMut
,
InNothing
,
}
struct
CheckStaticVisitor
<
'a
,
'tcx
:
'a
>
{
tcx
:
&
'a
ty
::
ctxt
<
'tcx
>
,
mode
:
Mode
,
checker
:
&
'a
mut
GlobalChecker
,
}
struct
GlobalVisitor
<
'a
,
'b
,
'tcx
:
'a
+
'b
>
(
euv
::
ExprUseVisitor
<
'a
,
'b
,
'tcx
,
ty
::
ParameterEnvironment
<
'b
,
'tcx
>>
);
struct
GlobalChecker
{
static_consumptions
:
NodeSet
,
const_borrows
:
NodeSet
,
static_interior_borrows
:
NodeSet
,
static_local_borrows
:
NodeSet
,
}
pub
fn
check_crate
(
tcx
:
&
ty
::
ctxt
)
{
let
mut
checker
=
GlobalChecker
{
static_consumptions
:
NodeSet
(),
const_borrows
:
NodeSet
(),
static_interior_borrows
:
NodeSet
(),
static_local_borrows
:
NodeSet
(),
};
{
let
param_env
=
ty
::
empty_parameter_environment
(
tcx
);
let
visitor
=
euv
::
ExprUseVisitor
::
new
(
&
mut
checker
,
&
param_env
);
visit
::
walk_crate
(
&
mut
GlobalVisitor
(
visitor
),
tcx
.map
.krate
());
}
visit
::
walk_crate
(
&
mut
CheckStaticVisitor
{
tcx
:
tcx
,
mode
:
InNothing
,
checker
:
&
mut
checker
,
},
tcx
.map
.krate
());
tcx
.sess
.abort_if_errors
();
}
impl
<
'a
,
'tcx
>
CheckStaticVisitor
<
'a
,
'tcx
>
{
fn
with_mode
<
F
>
(
&
mut
self
,
mode
:
Mode
,
f
:
F
)
where
F
:
FnOnce
(
&
mut
CheckStaticVisitor
<
'a
,
'tcx
>
),
{
let
old
=
self
.mode
;
self
.mode
=
mode
;
f
(
self
);
self
.mode
=
old
;
}
fn
msg
(
&
self
)
->
&
'static
str
{
match
self
.mode
{
InConstant
=>
"constants"
,
InStaticMut
|
InStatic
=>
"statics"
,
InNothing
=>
unreachable!
(),
}
}
fn
check_static_mut_type
(
&
self
,
e
:
&
ast
::
Expr
)
{
let
node_ty
=
ty
::
node_id_to_type
(
self
.tcx
,
e
.id
);
let
tcontents
=
ty
::
type_contents
(
self
.tcx
,
node_ty
);
let
suffix
=
if
tcontents
.has_dtor
()
{
"destructors"
}
else
if
tcontents
.owns_owned
()
{
"owned pointers"
}
else
{
return
};
self
.tcx.sess
.span_err
(
e
.span
,
&
format!
(
"mutable statics are not allowed
\
to have {}"
,
suffix
)[]);
}
fn
check_static_type
(
&
self
,
e
:
&
ast
::
Expr
)
{
let
ty
=
ty
::
node_id_to_type
(
self
.tcx
,
e
.id
);
let
infcx
=
infer
::
new_infer_ctxt
(
self
.tcx
);
let
mut
fulfill_cx
=
traits
::
FulfillmentContext
::
new
();
let
cause
=
traits
::
ObligationCause
::
new
(
e
.span
,
e
.id
,
traits
::
SharedStatic
);
fulfill_cx
.register_builtin_bound
(
&
infcx
,
ty
,
ty
::
BoundSync
,
cause
);
let
env
=
ty
::
empty_parameter_environment
(
self
.tcx
);
match
fulfill_cx
.select_all_or_error
(
&
infcx
,
&
env
)
{
Ok
(())
=>
{
},
Err
(
ref
errors
)
=>
{
traits
::
report_fulfillment_errors
(
&
infcx
,
errors
);
}
}
}
}
impl
<
'a
,
'tcx
,
'v
>
Visitor
<
'v
>
for
CheckStaticVisitor
<
'a
,
'tcx
>
{
fn
visit_item
(
&
mut
self
,
i
:
&
ast
::
Item
)
{
debug!
(
"visit_item(item={})"
,
pprust
::
item_to_string
(
i
));
match
i
.node
{
ast
::
ItemStatic
(
_
,
ast
::
MutImmutable
,
ref
expr
)
=>
{
self
.check_static_type
(
&**
expr
);
self
.with_mode
(
InStatic
,
|
v
|
v
.visit_expr
(
&**
expr
));
}
ast
::
ItemStatic
(
_
,
ast
::
MutMutable
,
ref
expr
)
=>
{
self
.check_static_mut_type
(
&**
expr
);
self
.with_mode
(
InStaticMut
,
|
v
|
v
.visit_expr
(
&**
expr
));
}
ast
::
ItemConst
(
_
,
ref
expr
)
=>
{
self
.with_mode
(
InConstant
,
|
v
|
v
.visit_expr
(
&**
expr
));
}
_
=>
{
self
.with_mode
(
InNothing
,
|
v
|
visit
::
walk_item
(
v
,
i
));
}
}
}
/// 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
)
{
if
self
.mode
==
InNothing
{
return
visit
::
walk_expr
(
self
,
e
);
}
let
node_ty
=
ty
::
node_id_to_type
(
self
.tcx
,
e
.id
);
match
node_ty
.sty
{
ty
::
ty_struct
(
did
,
_
)
|
ty
::
ty_enum
(
did
,
_
)
if
ty
::
has_dtor
(
self
.tcx
,
did
)
=>
{
self
.tcx.sess
.span_err
(
e
.span
,
&
format!
(
"{} are not allowed to have
\
destructors"
,
self
.msg
())[])
}
_
=>
{}
}
// statics cannot be consumed by value at any time, that would imply
// that they're an initializer (what a const is for) or kept in sync
// over time (not feasible), so deny it outright.
if
self
.checker.static_consumptions
.remove
(
&
e
.id
)
{
self
.tcx.sess
.span_err
(
e
.span
,
"cannot refer to other statics by
\
value, use the address-of operator
\
or a constant instead"
);
}
// Borrowed statics can specifically *only* have their address taken,
// not any number of other borrows such as borrowing fields, reading
// elements of an array, etc.
if
self
.checker.static_interior_borrows
.remove
(
&
e
.id
)
{
self
.tcx.sess
.span_err
(
e
.span
,
"cannot refer to the interior of
\
another static, use a constant
\
instead"
);
}
// constants cannot be borrowed if they contain interior mutability as
// it means that our "silent insertion of statics" could change
// initializer values (very bad).
if
self
.checker.const_borrows
.remove
(
&
e
.id
)
{
let
node_ty
=
ty
::
node_id_to_type
(
self
.tcx
,
e
.id
);
let
tcontents
=
ty
::
type_contents
(
self
.tcx
,
node_ty
);
if
tcontents
.interior_unsafe
()
{
self
.tcx.sess
.span_err
(
e
.span
,
"cannot borrow a constant which
\
contains interior mutability,
\
create a static instead"
);
}
}
// local variables in a block expression in a static context (i.e. being
// assigned to a static variable) cannot be borrowed.
if
self
.checker.static_local_borrows
.remove
(
&
e
.id
)
{
self
.tcx.sess
.span_err
(
e
.span
,
"cannot borrow a local variable inside
\
a static block, define a separate static
\
instead"
);
}
match
e
.node
{
ast
::
ExprAddrOf
(
ast
::
MutMutable
,
_
)
=>
{
if
self
.mode
!=
InStaticMut
{
span_err!
(
self
.tcx.sess
,
e
.span
,
E0020
,
"{} are not allowed to have mutable references"
,
self
.msg
());
}
},
ast
::
ExprBox
(
..
)
|
ast
::
ExprUnary
(
ast
::
UnUniq
,
_
)
=>
{
span_err!
(
self
.tcx.sess
,
e
.span
,
E0022
,
"{} are not allowed to have custom pointers"
,
self
.msg
());
}
ast
::
ExprPath
(
_
)
|
ast
::
ExprQPath
(
_
)
=>
{
match
ty
::
resolve_expr
(
self
.tcx
,
e
)
{
def
::
DefStatic
(
..
)
if
self
.mode
==
InConstant
=>
{
let
msg
=
"constants cannot refer to other statics,
\
insert an intermediate constant
\
instead"
;
self
.tcx.sess
.span_err
(
e
.span
,
&
msg
[]);
}
_
=>
{}
}
}
_
=>
{}
}
visit
::
walk_expr
(
self
,
e
);
}
}
impl
<
'a
,
'b
,
't
,
'v
>
Visitor
<
'v
>
for
GlobalVisitor
<
'a
,
'b
,
't
>
{
fn
visit_item
(
&
mut
self
,
item
:
&
ast
::
Item
)
{
match
item
.node
{
ast
::
ItemConst
(
_
,
ref
e
)
|
ast
::
ItemStatic
(
_
,
_
,
ref
e
)
=>
{
let
GlobalVisitor
(
ref
mut
v
)
=
*
self
;
v
.consume_expr
(
&**
e
);
}
_
=>
{}
}
visit
::
walk_item
(
self
,
item
);
}
}
impl
<
'tcx
>
euv
::
Delegate
<
'tcx
>
for
GlobalChecker
{
fn
consume
(
&
mut
self
,
consume_id
:
ast
::
NodeId
,
_
consume_span
:
Span
,
cmt
:
mc
::
cmt
,
_
mode
:
euv
::
ConsumeMode
)
{
let
mut
cur
=
&
cmt
;
loop
{
match
cur
.cat
{
mc
::
cat_static_item
=>
{
self
.static_consumptions
.insert
(
consume_id
);
break
}
mc
::
cat_deref
(
ref
cmt
,
_
,
_
)
|
mc
::
cat_downcast
(
ref
cmt
,
_
)
|
mc
::
cat_interior
(
ref
cmt
,
_
)
=>
cur
=
cmt
,
mc
::
cat_rvalue
(
..
)
|
mc
::
cat_upvar
(
..
)
|
mc
::
cat_local
(
..
)
=>
break
,
}
}
}
fn
borrow
(
&
mut
self
,
borrow_id
:
ast
::
NodeId
,
_
borrow_span
:
Span
,
cmt
:
mc
::
cmt
,
_
loan_region
:
ty
::
Region
,
_
bk
:
ty
::
BorrowKind
,
_
loan_cause
:
euv
::
LoanCause
)
{
let
mut
cur
=
&
cmt
;
let
mut
is_interior
=
false
;
loop
{
match
cur
.cat
{
mc
::
cat_rvalue
(
..
)
=>
{
self
.const_borrows
.insert
(
borrow_id
);
break
}
mc
::
cat_static_item
=>
{
if
is_interior
{
self
.static_interior_borrows
.insert
(
borrow_id
);
}
break
}
mc
::
cat_deref
(
ref
cmt
,
_
,
_
)
|
mc
::
cat_interior
(
ref
cmt
,
_
)
=>
{
is_interior
=
true
;
cur
=
cmt
;
}
mc
::
cat_downcast
(
..
)
|
mc
::
cat_upvar
(
..
)
=>
unreachable!
(),
mc
::
cat_local
(
..
)
=>
{
self
.static_local_borrows
.insert
(
borrow_id
);
break
}
}
}
}
fn
decl_without_init
(
&
mut
self
,
_
id
:
ast
::
NodeId
,
_
span
:
Span
)
{}
fn
mutate
(
&
mut
self
,
_
assignment_id
:
ast
::
NodeId
,
_
assignment_span
:
Span
,
_
assignee_cmt
:
mc
::
cmt
,
_
mode
:
euv
::
MutateMode
)
{}
fn
matched_pat
(
&
mut
self
,
_
:
&
ast
::
Pat
,
_
:
mc
::
cmt
,
_
:
euv
::
MatchMode
)
{}
fn
consume_pat
(
&
mut
self
,
_
consume_pat
:
&
ast
::
Pat
,
_
cmt
:
mc
::
cmt
,
_
mode
:
euv
::
ConsumeMode
)
{}
}
src/librustc_driver/driver.rs
浏览文件 @
4d8f995c
...
...
@@ -611,9 +611,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
// passes are timed inside typeck
typeck
::
check_crate
(
&
ty_cx
,
trait_map
);
time
(
time_passes
,
"check static items"
,
(),
|
_
|
middle
::
check_static
::
check_crate
(
&
ty_cx
));
time
(
time_passes
,
"const checking"
,
(),
|
_
|
middle
::
check_const
::
check_crate
(
&
ty_cx
));
...
...
src/test/compile-fail/check-static-immutable-mut-slices.rs
浏览文件 @
4d8f995c
...
...
@@ -11,6 +11,6 @@
// Checks that immutable static items can't have mutable slices
static
TEST
:
&
'static
mut
[
isize
]
=
&
mut
[];
//~^ ERROR
statics are not allowed to have mutable referenc
es
//~^ ERROR
references in statics may only refer to immutable valu
es
pub
fn
main
()
{
}
src/test/compile-fail/check-static-values-constraints.rs
浏览文件 @
4d8f995c
...
...
@@ -99,7 +99,7 @@ fn drop(&mut self) {}
struct
MyOwned
;
static
STATIC11
:
Box
<
MyOwned
>
=
box
MyOwned
;
//~^ ERROR
statics are not allowed to have custom pointer
s
//~^ ERROR
allocations are not allowed in static
s
// The following examples test that mutable structs are just forbidden
// to have types with destructors
...
...
@@ -117,16 +117,17 @@ fn drop(&mut self) {}
//~^ ERROR mutable statics are not allowed to have destructors
field1
:
SafeEnum
::
Variant1
,
field2
:
SafeEnum
::
Variant4
(
"str"
.to_string
())
//~^ ERROR static contains unimplemented expression type
};
static
STATIC15
:
&
'static
[
Box
<
MyOwned
>
]
=
&
[
box
MyOwned
,
//~ ERROR
statics are not allowed to have custom pointer
s
box
MyOwned
,
//~ ERROR
statics are not allowed to have custom pointer
s
box
MyOwned
,
//~ ERROR
allocations are not allowed in static
s
box
MyOwned
,
//~ ERROR
allocations are not allowed in static
s
];
static
STATIC16
:
(
&
'static
Box
<
MyOwned
>
,
&
'static
Box
<
MyOwned
>
)
=
(
&
box
MyOwned
,
//~ ERROR
statics are not allowed to have custom pointer
s
&
box
MyOwned
,
//~ ERROR
statics are not allowed to have custom pointer
s
&
box
MyOwned
,
//~ ERROR
allocations are not allowed in static
s
&
box
MyOwned
,
//~ ERROR
allocations are not allowed in static
s
);
static
mut
STATIC17
:
SafeEnum
=
SafeEnum
::
Variant1
;
...
...
@@ -134,9 +135,9 @@ fn drop(&mut self) {}
static
STATIC19
:
Box
<
isize
>
=
box
3
;
//~^ ERROR
statics are not allowed to have custom pointer
s
//~^ ERROR
allocations are not allowed in static
s
pub
fn
main
()
{
let
y
=
{
static
x
:
Box
<
isize
>
=
box
3
;
x
};
//~^ ERROR
statics are not allowed to have custom pointer
s
//~^ ERROR
allocations are not allowed in static
s
}
src/test/compile-fail/issue-17458.rs
浏览文件 @
4d8f995c
...
...
@@ -9,7 +9,7 @@
// except according to those terms.
static
X
:
usize
=
0
as
*
const
usize
as
usize
;
//~^ ERROR: can not cast a pointer to an integer in
a constant expression
//~^ ERROR: can not cast a pointer to an integer in
statics
fn
main
()
{
assert_eq!
(
X
,
0
);
...
...
src/test/compile-fail/issue-17718-const-bad-values.rs
浏览文件 @
4d8f995c
...
...
@@ -9,12 +9,12 @@
// except according to those terms.
const
C1
:
&
'static
mut
[
usize
]
=
&
mut
[];
//~^ ERROR:
constants are not allowed to have mutable referenc
es
//~^ ERROR:
references in constants may only refer to immutable valu
es
static
mut
S
:
usize
=
3
;
const
C2
:
&
'static
mut
usize
=
&
mut
S
;
//~^ ERROR: constants cannot refer to other statics
//~^^ ERROR:
are not allowed to have mutable referenc
es
//~^^ ERROR:
references in constants may only refer to immutable valu
es
fn
main
()
{}
src/test/compile-fail/issue-18118.rs
浏览文件 @
4d8f995c
...
...
@@ -11,7 +11,8 @@
pub
fn
main
()
{
static
z
:
&
'static
isize
=
{
let
p
=
3
;
//~^ ERROR blocks in constants are limited to items and tail expressions
&
p
//~^ ERROR cannot borrow a local variable inside a static block, define a separate static instead
//~^ ERROR paths in constants may only refer to constants or functions
};
}
src/test/compile-fail/issue-7364.rs
浏览文件 @
4d8f995c
...
...
@@ -14,8 +14,9 @@
// Regression test for issue 7364
static
boxed
:
Box
<
RefCell
<
isize
>>
=
box
RefCell
::
new
(
0
);
//~^ ERROR
statics are not allowed to have custom pointer
s
//~^ ERROR
allocations are not allowed in static
s
//~| ERROR: the trait `core::marker::Sync` is not implemented for the type
//~| ERROR: the trait `core::marker::Sync` is not implemented for the type
//~^^^^^ ERROR function calls in constants are limited to struct and enum constructors
fn
main
()
{
}
src/test/compile-fail/static-mut-not-constant.rs
浏览文件 @
4d8f995c
...
...
@@ -11,7 +11,7 @@
#![feature(box_syntax)]
static
mut
a
:
Box
<
isize
>
=
box
3
;
//~^ ERROR
statics are not allowed to have custom pointer
s
//~^ ERROR
allocations are not allowed in static
s
//~^^ ERROR mutable statics are not allowed to have owned pointers
fn
main
()
{}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录