Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
8878a403
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,发现更多精彩内容 >>
提交
8878a403
编写于
2月 28, 2017
作者:
O
Oliver Schneider
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
rustup to rustc 1.17.0-nightly (
60a0edc6
2017-02-26)
上级
feeb13c4
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
215 addition
and
102 deletion
+215
-102
src/eval_context.rs
src/eval_context.rs
+11
-6
src/memory.rs
src/memory.rs
+23
-6
src/terminator/mod.rs
src/terminator/mod.rs
+144
-86
src/traits.rs
src/traits.rs
+21
-2
tests/run-pass/non_capture_closure_to_fn_ptr.rs
tests/run-pass/non_capture_closure_to_fn_ptr.rs
+16
-0
tests/run-pass/recursive_static.rs
tests/run-pass/recursive_static.rs
+0
-2
未找到文件。
src/eval_context.rs
浏览文件 @
8878a403
...
...
@@ -649,16 +649,21 @@ pub(super) fn eval_rvalue_into_lvalue(
},
UnsafeFnPointer
=>
match
dest_ty
.sty
{
ty
::
TyFnPtr
(
unsafe_fn_ty
)
=>
{
ty
::
TyFnPtr
(
_
)
=>
{
let
src
=
self
.eval_operand
(
operand
)
?
;
let
ptr
=
src
.read_ptr
(
&
self
.memory
)
?
;
let
fn_def
=
self
.memory
.get_fn
(
ptr
.alloc_id
)
?
.expect_concrete
()
?
;
let
unsafe_fn_ty
=
self
.tcx
.erase_regions
(
&
unsafe_fn_ty
);
let
fn_ptr
=
self
.memory
.create_fn_ptr
(
self
.tcx
,
fn_def
.def_id
,
fn_def
.substs
,
unsafe_fn_ty
);
self
.write_value
(
Value
::
ByVal
(
PrimVal
::
Ptr
(
fn_ptr
)),
dest
,
dest_ty
)
?
;
self
.write_value
(
src
,
dest
,
dest_ty
)
?
;
},
ref
other
=>
bug!
(
"fn to unsafe fn cast on {:?}"
,
other
),
},
ClosureFnPointer
=>
match
self
.operand_ty
(
operand
)
.sty
{
ty
::
TyClosure
(
def_id
,
substs
)
=>
{
let
fn_ty
=
self
.tcx
.closure_type
(
def_id
,
substs
);
let
fn_ptr
=
self
.memory
.create_fn_ptr_from_noncapture_closure
(
self
.tcx
,
def_id
,
substs
,
fn_ty
);
self
.write_value
(
Value
::
ByVal
(
PrimVal
::
Ptr
(
fn_ptr
)),
dest
,
dest_ty
)
?
;
},
ref
other
=>
bug!
(
"reify fn pointer on {:?}"
,
other
),
},
}
}
...
...
src/memory.rs
浏览文件 @
8878a403
...
...
@@ -130,15 +130,11 @@ pub enum Function<'tcx> {
FnPtrAsTraitObject
(
&
'tcx
ty
::
FnSig
<
'tcx
>
),
/// Glue for Closures
Closure
(
FunctionDefinition
<
'tcx
>
),
/// Glue for noncapturing closures casted to function pointers
NonCaptureClosureAsFnPtr
(
FunctionDefinition
<
'tcx
>
),
}
impl
<
'tcx
>
Function
<
'tcx
>
{
pub
fn
expect_concrete
(
self
)
->
EvalResult
<
'tcx
,
FunctionDefinition
<
'tcx
>>
{
match
self
{
Function
::
Concrete
(
fn_def
)
=>
Ok
(
fn_def
),
other
=>
Err
(
EvalError
::
ExpectedConcreteFunction
(
other
)),
}
}
pub
fn
expect_drop_glue_real_ty
(
self
)
->
EvalResult
<
'tcx
,
ty
::
Ty
<
'tcx
>>
{
match
self
{
Function
::
DropGlue
(
real_ty
)
=>
Ok
(
real_ty
),
...
...
@@ -238,6 +234,23 @@ pub fn create_closure_ptr(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId,
}))
}
pub
fn
create_fn_ptr_from_noncapture_closure
(
&
mut
self
,
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
def_id
:
DefId
,
substs
:
ClosureSubsts
<
'tcx
>
,
fn_ty
:
ClosureTy
<
'tcx
>
)
->
Pointer
{
// FIXME: this is a hack
let
fn_ty
=
tcx
.mk_bare_fn
(
ty
::
BareFnTy
{
unsafety
:
fn_ty
.unsafety
,
abi
:
fn_ty
.abi
,
sig
:
fn_ty
.sig
,
});
self
.create_fn_alloc
(
Function
::
NonCaptureClosureAsFnPtr
(
FunctionDefinition
{
def_id
,
substs
:
substs
.substs
,
abi
:
Abi
::
Rust
,
// adjust abi
// FIXME: why doesn't this compile?
//sig: tcx.erase_late_bound_regions(&fn_ty.sig),
sig
:
fn_ty
.sig
.skip_binder
(),
}))
}
pub
fn
create_fn_as_trait_glue
(
&
mut
self
,
_
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
def_id
:
DefId
,
substs
:
&
'tcx
Substs
<
'tcx
>
,
fn_ty
:
&
'tcx
BareFnTy
<
'tcx
>
)
->
Pointer
{
self
.create_fn_alloc
(
Function
::
FnDefAsTraitObject
(
FunctionDefinition
{
def_id
,
...
...
@@ -535,6 +548,10 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
trace!
(
"{} closure glue for {}"
,
msg
,
dump_fn_def
(
fn_def
));
continue
;
},
(
None
,
Some
(
&
Function
::
NonCaptureClosureAsFnPtr
(
fn_def
)))
=>
{
trace!
(
"{} non-capture closure as fn ptr glue for {}"
,
msg
,
dump_fn_def
(
fn_def
));
continue
;
},
(
None
,
None
)
=>
{
trace!
(
"{} (deallocated)"
,
msg
);
continue
;
...
...
src/terminator/mod.rs
浏览文件 @
8878a403
...
...
@@ -2,14 +2,14 @@
use
rustc
::
mir
;
use
rustc
::
ty
::
layout
::
Layout
;
use
rustc
::
ty
::
subst
::
Substs
;
use
rustc
::
ty
::{
self
,
Ty
,
BareFnTy
};
use
rustc
::
ty
::{
self
,
Ty
};
use
syntax
::
codemap
::
Span
;
use
syntax
::
attr
;
use
error
::{
EvalError
,
EvalResult
};
use
eval_context
::{
EvalContext
,
IntegerExt
,
StackPopCleanup
,
is_inhabited
};
use
lvalue
::
Lvalue
;
use
memory
::{
Pointer
,
FunctionDefinition
};
use
memory
::{
Pointer
,
FunctionDefinition
,
Function
};
use
value
::
PrimVal
;
use
value
::
Value
;
...
...
@@ -61,35 +61,54 @@ pub(super) fn eval_terminator(
};
let
func_ty
=
self
.operand_ty
(
func
);
match
func_ty
.sty
{
let
fn_def
=
match
func_ty
.sty
{
ty
::
TyFnPtr
(
bare_fn_ty
)
=>
{
let
fn_ptr
=
self
.eval_operand_to_primval
(
func
)
?
.to_ptr
()
?
;
let
FunctionDefinition
{
def_id
,
substs
,
abi
,
sig
}
=
self
.memory
.get_fn
(
fn_ptr
.alloc_id
)
?
.expect_concrete
(
)
?
;
let
fn_def
=
self
.memory
.get_fn
(
fn_ptr
.alloc_id
)
?
;
let
bare_sig
=
self
.tcx
.erase_late_bound_regions_and_normalize
(
&
bare_fn_ty
.sig
);
let
bare_sig
=
self
.tcx
.erase_regions
(
&
bare_sig
);
// transmuting function pointers in miri is fine as long as the number of
// arguments and the abi don't change.
// FIXME: also check the size of the arguments' type and the return type
// Didn't get it to work, since that triggers an assertion in rustc which
// checks whether the type has escaping regions
if
abi
!=
bare_fn_ty
.abi
||
sig
.variadic
!=
bare_sig
.variadic
||
sig
.inputs
()
.len
()
!=
bare_sig
.inputs
()
.len
()
{
return
Err
(
EvalError
::
FunctionPointerTyMismatch
(
abi
,
sig
,
bare_fn_ty
));
match
fn_def
{
Function
::
Concrete
(
fn_def
)
=>
{
// transmuting function pointers in miri is fine as long as the number of
// arguments and the abi don't change.
// FIXME: also check the size of the arguments' type and the return type
// Didn't get it to work, since that triggers an assertion in rustc which
// checks whether the type has escaping regions
if
fn_def
.abi
!=
bare_fn_ty
.abi
||
fn_def
.sig.variadic
!=
bare_sig
.variadic
||
fn_def
.sig
.inputs
()
.len
()
!=
bare_sig
.inputs
()
.len
()
{
return
Err
(
EvalError
::
FunctionPointerTyMismatch
(
fn_def
.abi
,
fn_def
.sig
,
bare_fn_ty
));
}
},
Function
::
NonCaptureClosureAsFnPtr
(
fn_def
)
=>
{
if
fn_def
.abi
!=
bare_fn_ty
.abi
||
fn_def
.sig.variadic
!=
bare_sig
.variadic
||
fn_def
.sig
.inputs
()
.len
()
!=
1
{
return
Err
(
EvalError
::
FunctionPointerTyMismatch
(
fn_def
.abi
,
fn_def
.sig
,
bare_fn_ty
));
}
if
let
ty
::
TyTuple
(
fields
,
_
)
=
fn_def
.sig
.inputs
()[
0
]
.sty
{
if
fields
.len
()
!=
bare_sig
.inputs
()
.len
()
{
return
Err
(
EvalError
::
FunctionPointerTyMismatch
(
fn_def
.abi
,
fn_def
.sig
,
bare_fn_ty
));
}
}
},
other
=>
return
Err
(
EvalError
::
ExpectedConcreteFunction
(
other
)),
}
self
.eval_fn_call
(
def_id
,
substs
,
bare_fn_ty
,
destination
,
args
,
terminator
.source_info.span
)
?
self
.memory
.get_fn
(
fn_ptr
.alloc_id
)
?
},
ty
::
TyFnDef
(
def_id
,
substs
,
fn_ty
)
=>
{
self
.eval_fn_call
(
def_id
,
substs
,
fn_ty
,
destination
,
args
,
terminator
.source_info.span
)
?
}
ty
::
TyFnDef
(
def_id
,
substs
,
fn_ty
)
=>
Function
::
Concrete
(
FunctionDefinition
{
def_id
,
substs
,
abi
:
fn_ty
.abi
,
sig
:
fn_ty
.sig
.skip_binder
(),
}),
_
=>
{
let
msg
=
format!
(
"can't handle callee of type {:?}"
,
func_ty
);
return
Err
(
EvalError
::
Unimplemented
(
msg
));
}
}
};
self
.eval_fn_call
(
fn_def
,
destination
,
args
,
terminator
.source_info.span
)
?
;
}
Drop
{
ref
location
,
target
,
..
}
=>
{
...
...
@@ -138,17 +157,16 @@ pub(super) fn eval_terminator(
fn
eval_fn_call
(
&
mut
self
,
def_id
:
DefId
,
substs
:
&
'tcx
Substs
<
'tcx
>
,
fn_ty
:
&
'tcx
BareFnTy
,
fn_def
:
Function
<
'tcx
>
,
destination
:
Option
<
(
Lvalue
<
'tcx
>
,
mir
::
BasicBlock
)
>
,
arg_operands
:
&
[
mir
::
Operand
<
'tcx
>
],
span
:
Span
,
)
->
EvalResult
<
'tcx
>
{
use
syntax
::
abi
::
Abi
;
match
fn_ty
.abi
{
Abi
::
RustIntrinsic
=>
{
let
ty
=
fn_ty
.sig
.0
.output
();
match
fn_def
{
// Intrinsics can only be addressed directly
Function
::
Concrete
(
FunctionDefinition
{
def_id
,
substs
,
abi
:
Abi
::
RustIntrinsic
,
sig
})
=>
{
let
ty
=
sig
.output
();
let
layout
=
self
.type_layout
(
ty
)
?
;
let
(
ret
,
target
)
=
match
destination
{
Some
(
dest
)
if
is_inhabited
(
self
.tcx
,
ty
)
=>
dest
,
...
...
@@ -157,18 +175,19 @@ fn eval_fn_call(
self
.call_intrinsic
(
def_id
,
substs
,
arg_operands
,
ret
,
ty
,
layout
,
target
)
?
;
self
.dump_local
(
ret
);
Ok
(())
}
Abi
::
C
=>
{
let
ty
=
fn_ty
.sig
.0
.output
();
}
,
// C functions can only be addressed directly
Function
::
Concrete
(
FunctionDefinition
{
def_id
,
abi
:
Abi
::
C
,
sig
,
..
})
=>
{
let
ty
=
sig
.output
();
let
(
ret
,
target
)
=
destination
.unwrap
();
self
.call_c_abi
(
def_id
,
arg_operands
,
ret
,
ty
)
?
;
self
.dump_local
(
ret
);
self
.goto_block
(
target
);
Ok
(())
}
Abi
::
Rust
|
Abi
::
RustCall
=>
{
},
Function
::
DropGlue
(
_
)
=>
Err
(
EvalError
::
ManuallyCalledDropGlue
),
Function
::
Concrete
(
FunctionDefinition
{
def_id
,
abi
:
Abi
::
RustCall
,
sig
,
substs
})
|
Function
::
Concrete
(
FunctionDefinition
{
def_id
,
abi
:
Abi
::
Rust
,
sig
,
substs
})
=>
{
let
mut
args
=
Vec
::
new
();
for
arg
in
arg_operands
{
let
arg_val
=
self
.eval_operand
(
arg
)
?
;
...
...
@@ -185,7 +204,7 @@ fn eval_fn_call(
};
// FIXME(eddyb) Detect ADT constructors more efficiently.
if
let
Some
(
adt_def
)
=
fn_ty
.sig
.skip_binder
()
.output
()
.ty_adt_def
()
{
if
let
Some
(
adt_def
)
=
sig
.output
()
.ty_adt_def
()
{
if
let
Some
(
v
)
=
adt_def
.variants
.iter
()
.find
(|
v
|
resolved_def_id
==
v
.did
)
{
let
(
lvalue
,
target
)
=
destination
.expect
(
"tuple struct constructors can't diverge"
);
let
dest_ty
=
self
.tcx
.item_type
(
adt_def
.did
);
...
...
@@ -240,66 +259,105 @@ fn eval_fn_call(
return
Ok
(());
}
}
let
mir
=
match
self
.load_mir
(
resolved_def_id
)
{
Ok
(
mir
)
=>
mir
,
Err
(
EvalError
::
NoMirFor
(
path
))
=>
{
match
&
path
[
..
]
{
// let's just ignore all output for now
"std::io::_print"
=>
{
self
.goto_block
(
destination
.unwrap
()
.1
);
return
Ok
(());
},
"std::thread::Builder::new"
=>
return
Err
(
EvalError
::
Unimplemented
(
"miri does not support threading"
.to_owned
())),
"std::env::args"
=>
return
Err
(
EvalError
::
Unimplemented
(
"miri does not support program arguments"
.to_owned
())),
"std::panicking::rust_panic_with_hook"
|
"std::rt::begin_panic_fmt"
=>
return
Err
(
EvalError
::
Panic
),
"std::panicking::panicking"
|
"std::rt::panicking"
=>
{
let
(
lval
,
block
)
=
destination
.expect
(
"std::rt::panicking does not diverge"
);
// we abort on panic -> `std::rt::panicking` always returns false
let
bool
=
self
.tcx.types.bool
;
self
.write_primval
(
lval
,
PrimVal
::
from_bool
(
false
),
bool
)
?
;
self
.goto_block
(
block
);
return
Ok
(());
}
_
=>
{},
}
return
Err
(
EvalError
::
NoMirFor
(
path
));
},
Err
(
other
)
=>
return
Err
(
other
),
};
let
(
return_lvalue
,
return_to_block
)
=
match
destination
{
Some
((
lvalue
,
block
))
=>
(
lvalue
,
StackPopCleanup
::
Goto
(
block
)),
None
=>
{
// FIXME(solson)
let
lvalue
=
Lvalue
::
from_ptr
(
Pointer
::
never_ptr
());
(
lvalue
,
StackPopCleanup
::
None
)
}
};
self
.push_stack_frame
(
self
.eval_fn_call_inner
(
resolved_def_id
,
span
,
mir
,
resolved_substs
,
return_lvalue
,
return_to_block
,
destination
,
args
,
temporaries
,
)
?
;
let
arg_locals
=
self
.frame
()
.mir
.args_iter
();
assert_eq!
(
self
.frame
()
.mir.arg_count
,
args
.len
());
for
(
arg_local
,
(
arg_val
,
arg_ty
))
in
arg_locals
.zip
(
args
)
{
let
dest
=
self
.eval_lvalue
(
&
mir
::
Lvalue
::
Local
(
arg_local
))
?
;
self
.write_value
(
arg_val
,
dest
,
arg_ty
)
?
;
span
,
)
},
Function
::
NonCaptureClosureAsFnPtr
(
FunctionDefinition
{
def_id
,
abi
:
Abi
::
Rust
,
substs
,
sig
})
=>
{
let
mut
args
=
Vec
::
new
();
for
arg
in
arg_operands
{
let
arg_val
=
self
.eval_operand
(
arg
)
?
;
let
arg_ty
=
self
.operand_ty
(
arg
);
args
.push
((
arg_val
,
arg_ty
));
}
args
.insert
(
0
,
(
Value
::
ByVal
(
PrimVal
::
Undef
),
sig
.inputs
()[
0
],
));
self
.eval_fn_call_inner
(
def_id
,
substs
,
destination
,
args
,
Vec
::
new
(),
span
,
)
}
other
=>
Err
(
EvalError
::
Unimplemented
(
format!
(
"can't call function kind {:?}"
,
other
))),
}
}
Ok
(())
fn
eval_fn_call_inner
(
&
mut
self
,
resolved_def_id
:
DefId
,
resolved_substs
:
&
'tcx
Substs
,
destination
:
Option
<
(
Lvalue
<
'tcx
>
,
mir
::
BasicBlock
)
>
,
args
:
Vec
<
(
Value
,
Ty
<
'tcx
>
)
>
,
temporaries
:
Vec
<
(
Pointer
,
Ty
<
'tcx
>
)
>
,
span
:
Span
,
)
->
EvalResult
<
'tcx
>
{
trace!
(
"eval_fn_call_inner: {:#?}, {:#?}, {:#?}"
,
args
,
temporaries
,
destination
);
let
mir
=
match
self
.load_mir
(
resolved_def_id
)
{
Ok
(
mir
)
=>
mir
,
Err
(
EvalError
::
NoMirFor
(
path
))
=>
{
match
&
path
[
..
]
{
// let's just ignore all output for now
"std::io::_print"
=>
{
self
.goto_block
(
destination
.unwrap
()
.1
);
return
Ok
(());
},
"std::thread::Builder::new"
=>
return
Err
(
EvalError
::
Unimplemented
(
"miri does not support threading"
.to_owned
())),
"std::env::args"
=>
return
Err
(
EvalError
::
Unimplemented
(
"miri does not support program arguments"
.to_owned
())),
"std::panicking::rust_panic_with_hook"
|
"std::rt::begin_panic_fmt"
=>
return
Err
(
EvalError
::
Panic
),
"std::panicking::panicking"
|
"std::rt::panicking"
=>
{
let
(
lval
,
block
)
=
destination
.expect
(
"std::rt::panicking does not diverge"
);
// we abort on panic -> `std::rt::panicking` always returns false
let
bool
=
self
.tcx.types.bool
;
self
.write_primval
(
lval
,
PrimVal
::
from_bool
(
false
),
bool
)
?
;
self
.goto_block
(
block
);
return
Ok
(());
}
_
=>
{},
}
return
Err
(
EvalError
::
NoMirFor
(
path
));
},
Err
(
other
)
=>
return
Err
(
other
),
};
let
(
return_lvalue
,
return_to_block
)
=
match
destination
{
Some
((
lvalue
,
block
))
=>
(
lvalue
,
StackPopCleanup
::
Goto
(
block
)),
None
=>
{
// FIXME(solson)
let
lvalue
=
Lvalue
::
from_ptr
(
Pointer
::
never_ptr
());
(
lvalue
,
StackPopCleanup
::
None
)
}
};
abi
=>
Err
(
EvalError
::
Unimplemented
(
format!
(
"can't handle function with {:?} ABI"
,
abi
))),
self
.push_stack_frame
(
resolved_def_id
,
span
,
mir
,
resolved_substs
,
return_lvalue
,
return_to_block
,
temporaries
,
)
?
;
let
arg_locals
=
self
.frame
()
.mir
.args_iter
();
assert_eq!
(
self
.frame
()
.mir.arg_count
,
args
.len
());
for
(
arg_local
,
(
arg_val
,
arg_ty
))
in
arg_locals
.zip
(
args
)
{
let
dest
=
self
.eval_lvalue
(
&
mir
::
Lvalue
::
Local
(
arg_local
))
?
;
self
.write_value
(
arg_val
,
dest
,
arg_ty
)
?
;
}
Ok
(())
}
pub
fn
read_discriminant_value
(
&
self
,
adt_ptr
:
Pointer
,
adt_ty
:
Ty
<
'tcx
>
)
->
EvalResult
<
'tcx
,
u128
>
{
...
...
src/traits.rs
浏览文件 @
8878a403
...
...
@@ -130,6 +130,13 @@ pub(crate) fn trait_method(
);
Ok
((
fn_def
.def_id
,
fn_def
.substs
,
Vec
::
new
()))
},
Function
::
NonCaptureClosureAsFnPtr
(
fn_def
)
=>
{
args
.insert
(
0
,
(
Value
::
ByVal
(
PrimVal
::
Undef
),
fn_def
.sig
.inputs
()[
0
],
));
Ok
((
fn_def
.def_id
,
fn_def
.substs
,
Vec
::
new
()))
}
Function
::
Closure
(
fn_def
)
=>
{
self
.unpack_fn_args
(
args
)
?
;
Ok
((
fn_def
.def_id
,
fn_def
.substs
,
Vec
::
new
()))
...
...
@@ -140,8 +147,20 @@ pub(crate) fn trait_method(
args
.remove
(
0
);
self
.unpack_fn_args
(
args
)
?
;
let
fn_ptr
=
self
.memory
.read_ptr
(
self_ptr
)
?
;
let
fn_def
=
self
.memory
.get_fn
(
fn_ptr
.alloc_id
)
?
.expect_concrete
()
?
;
assert_eq!
(
sig
,
fn_def
.sig
);
let
fn_def
=
match
self
.memory
.get_fn
(
fn_ptr
.alloc_id
)
?
{
Function
::
Concrete
(
fn_def
)
=>
{
assert_eq!
(
sig
,
fn_def
.sig
);
fn_def
},
Function
::
NonCaptureClosureAsFnPtr
(
fn_def
)
=>
{
args
.insert
(
0
,
(
Value
::
ByVal
(
PrimVal
::
Undef
),
fn_def
.sig
.inputs
()[
0
],
));
fn_def
},
other
=>
bug!
(
"FnPtrAsTraitObject for {:?}"
,
other
),
};
Ok
((
fn_def
.def_id
,
fn_def
.substs
,
Vec
::
new
()))
}
}
...
...
tests/run-pass/non_capture_closure_to_fn_ptr.rs
0 → 100644
浏览文件 @
8878a403
#![feature(closure_to_fn_coercion)]
// allow(const_err) to work around a bug in warnings
#[allow(const_err)]
static
FOO
:
fn
()
=
||
{
assert_ne!
(
42
,
43
)
};
#[allow(const_err)]
static
BAR
:
fn
(
i32
,
i32
)
=
|
a
,
b
|
{
assert_ne!
(
a
,
b
)
};
fn
main
()
{
FOO
();
BAR
(
44
,
45
);
let
bar
:
unsafe
fn
(
i32
,
i32
)
=
BAR
;
unsafe
{
bar
(
46
,
47
)
};
let
boo
:
&
Fn
(
i32
,
i32
)
=
&
BAR
;
boo
(
48
,
49
);
}
tests/run-pass/recursive_static.rs
浏览文件 @
8878a403
#![feature(static_recursion)]
struct
S
(
&
'static
S
);
static
S1
:
S
=
S
(
&
S2
);
static
S2
:
S
=
S
(
&
S1
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录