Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
6a2666d5
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,发现更多精彩内容 >>
提交
6a2666d5
编写于
8月 30, 2016
作者:
M
Michael Woerister
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ICH: Add ability to test the ICH of exported metadata items.
上级
f2c53ea6
变更
13
显示空白变更内容
内联
并排
Showing
13 changed file
with
622 addition
and
115 deletion
+622
-115
src/librustc_incremental/assert_dep_graph.rs
src/librustc_incremental/assert_dep_graph.rs
+4
-6
src/librustc_incremental/calculate_svh/mod.rs
src/librustc_incremental/calculate_svh/mod.rs
+38
-2
src/librustc_incremental/calculate_svh/svh_visitor.rs
src/librustc_incremental/calculate_svh/svh_visitor.rs
+9
-3
src/librustc_incremental/lib.rs
src/librustc_incremental/lib.rs
+7
-0
src/librustc_incremental/persist/data.rs
src/librustc_incremental/persist/data.rs
+13
-0
src/librustc_incremental/persist/directory.rs
src/librustc_incremental/persist/directory.rs
+0
-1
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_incremental/persist/dirty_clean.rs
+141
-51
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/load.rs
+55
-1
src/librustc_incremental/persist/save.rs
src/librustc_incremental/persist/save.rs
+62
-17
src/libsyntax/feature_gate.rs
src/libsyntax/feature_gate.rs
+10
-0
src/test/incremental/hashes/struct_defs.rs
src/test/incremental/hashes/struct_defs.rs
+238
-0
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/header.rs
+24
-26
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/runtest.rs
+21
-8
未找到文件。
src/librustc_incremental/assert_dep_graph.rs
浏览文件 @
6a2666d5
...
...
@@ -59,9 +59,7 @@
use
syntax
::
ast
;
use
syntax
::
parse
::
token
::
InternedString
;
use
syntax_pos
::
Span
;
const
IF_THIS_CHANGED
:
&
'static
str
=
"rustc_if_this_changed"
;
const
THEN_THIS_WOULD_NEED
:
&
'static
str
=
"rustc_then_this_would_need"
;
use
{
ATTR_IF_THIS_CHANGED
,
ATTR_THEN_THIS_WOULD_NEED
};
pub
fn
assert_dep_graph
<
'a
,
'tcx
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
)
{
let
_
ignore
=
tcx
.dep_graph
.in_ignore
();
...
...
@@ -91,7 +89,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
assert
!
(
tcx
.sess.opts.debugging_opts.query_dep_graph
,
"cannot use the `#[{}]` or `#[{}]` annotations
\
without supplying `-Z query-dep-graph`"
,
IF_THIS_CHANGED
,
THEN_THIS_WOULD_NEED
);
ATTR_IF_THIS_CHANGED
,
ATTR_
THEN_THIS_WOULD_NEED
);
}
// Check paths.
...
...
@@ -125,7 +123,7 @@ fn argument(&self, attr: &ast::Attribute) -> Option<InternedString> {
fn
process_attrs
(
&
mut
self
,
node_id
:
ast
::
NodeId
,
attrs
:
&
[
ast
::
Attribute
])
{
let
def_id
=
self
.tcx.map
.local_def_id
(
node_id
);
for
attr
in
attrs
{
if
attr
.check_name
(
IF_THIS_CHANGED
)
{
if
attr
.check_name
(
ATTR_
IF_THIS_CHANGED
)
{
let
dep_node_interned
=
self
.argument
(
attr
);
let
dep_node
=
match
dep_node_interned
{
None
=>
DepNode
::
Hir
(
def_id
),
...
...
@@ -141,7 +139,7 @@ fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
}
};
self
.if_this_changed
.push
((
attr
.span
,
def_id
,
dep_node
));
}
else
if
attr
.check_name
(
THEN_THIS_WOULD_NEED
)
{
}
else
if
attr
.check_name
(
ATTR_
THEN_THIS_WOULD_NEED
)
{
let
dep_node_interned
=
self
.argument
(
attr
);
let
dep_node
=
match
dep_node_interned
{
Some
(
ref
n
)
=>
{
...
...
src/librustc_incremental/calculate_svh/mod.rs
浏览文件 @
6a2666d5
...
...
@@ -28,6 +28,7 @@
//! at the beginning.
use
syntax
::
ast
;
use
std
::
cell
::
RefCell
;
use
std
::
hash
::{
Hash
,
SipHasher
,
Hasher
};
use
rustc
::
dep_graph
::
DepNode
;
use
rustc
::
hir
;
...
...
@@ -46,7 +47,42 @@
mod
svh_visitor
;
mod
caching_codemap_view
;
pub
type
IncrementalHashesMap
=
FnvHashMap
<
DepNode
<
DefId
>
,
u64
>
;
pub
struct
IncrementalHashesMap
{
hashes
:
FnvHashMap
<
DepNode
<
DefId
>
,
u64
>
,
// These are the metadata hashes for the current crate as they were stored
// during the last compilation session. They are only loaded if
// -Z query-dep-graph was specified and are needed for auto-tests using
// the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
// check whether some metadata hash has changed in between two revisions.
pub
prev_metadata_hashes
:
RefCell
<
FnvHashMap
<
DefId
,
u64
>>
,
}
impl
IncrementalHashesMap
{
pub
fn
new
()
->
IncrementalHashesMap
{
IncrementalHashesMap
{
hashes
:
FnvHashMap
(),
prev_metadata_hashes
:
RefCell
::
new
(
FnvHashMap
()),
}
}
pub
fn
insert
(
&
mut
self
,
k
:
DepNode
<
DefId
>
,
v
:
u64
)
->
Option
<
u64
>
{
self
.hashes
.insert
(
k
,
v
)
}
pub
fn
iter
<
'a
>
(
&
'a
self
)
->
::
std
::
collections
::
hash_map
::
Iter
<
'a
,
DepNode
<
DefId
>
,
u64
>
{
self
.hashes
.iter
()
}
}
impl
<
'a
>
::
std
::
ops
::
Index
<&
'a
DepNode
<
DefId
>>
for
IncrementalHashesMap
{
type
Output
=
u64
;
fn
index
(
&
self
,
index
:
&
'a
DepNode
<
DefId
>
)
->
&
u64
{
&
self
.hashes
[
index
]
}
}
pub
fn
compute_incremental_hashes_map
<
'a
,
'tcx
:
'a
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
)
->
IncrementalHashesMap
{
...
...
@@ -55,7 +91,7 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
let
hash_spans
=
tcx
.sess.opts.debuginfo
!=
NoDebugInfo
;
let
mut
visitor
=
HashItemsVisitor
{
tcx
:
tcx
,
hashes
:
FnvHashMap
(),
hashes
:
IncrementalHashesMap
::
new
(),
def_path_hashes
:
DefPathHashes
::
new
(
tcx
),
codemap
:
CachingCodemapView
::
new
(
tcx
),
hash_spans
:
hash_spans
,
...
...
src/librustc_incremental/calculate_svh/svh_visitor.rs
浏览文件 @
6a2666d5
...
...
@@ -30,9 +30,15 @@
use
super
::
def_path_hash
::
DefPathHashes
;
use
super
::
caching_codemap_view
::
CachingCodemapView
;
const
IGNORED_ATTRIBUTES
:
&
'static
[
&
'static
str
]
=
&
[
"cfg"
,
"rustc_clean"
,
"rustc_dirty"
];
const
IGNORED_ATTRIBUTES
:
&
'static
[
&
'static
str
]
=
&
[
"cfg"
,
::
ATTR_IF_THIS_CHANGED
,
::
ATTR_THEN_THIS_WOULD_NEED
,
::
ATTR_DIRTY
,
::
ATTR_CLEAN
,
::
ATTR_DIRTY_METADATA
,
::
ATTR_CLEAN_METADATA
];
pub
struct
StrictVersionHashVisitor
<
'a
,
'hash
:
'a
,
'tcx
:
'hash
>
{
pub
tcx
:
TyCtxt
<
'hash
,
'tcx
,
'tcx
>
,
...
...
src/librustc_incremental/lib.rs
浏览文件 @
6a2666d5
...
...
@@ -35,6 +35,13 @@
#[macro_use]
extern
crate
syntax
;
extern
crate
syntax_pos
;
const
ATTR_DIRTY
:
&
'static
str
=
"rustc_dirty"
;
const
ATTR_CLEAN
:
&
'static
str
=
"rustc_clean"
;
const
ATTR_DIRTY_METADATA
:
&
'static
str
=
"rustc_metadata_dirty"
;
const
ATTR_CLEAN_METADATA
:
&
'static
str
=
"rustc_metadata_clean"
;
const
ATTR_IF_THIS_CHANGED
:
&
'static
str
=
"rustc_if_this_changed"
;
const
ATTR_THEN_THIS_WOULD_NEED
:
&
'static
str
=
"rustc_then_this_would_need"
;
mod
assert_dep_graph
;
mod
calculate_svh
;
mod
persist
;
...
...
src/librustc_incremental/persist/data.rs
浏览文件 @
6a2666d5
...
...
@@ -13,6 +13,7 @@
use
rustc
::
dep_graph
::{
DepNode
,
WorkProduct
,
WorkProductId
};
use
rustc
::
hir
::
def_id
::
DefIndex
;
use
std
::
sync
::
Arc
;
use
rustc_data_structures
::
fnv
::
FnvHashMap
;
use
super
::
directory
::
DefPathIndex
;
...
...
@@ -93,6 +94,18 @@ pub struct SerializedMetadataHashes {
/// a `DefPathIndex` that gets retracted to the current `DefId`
/// (matching the one found in this structure).
pub
hashes
:
Vec
<
SerializedMetadataHash
>
,
/// For each DefIndex (as it occurs in SerializedMetadataHash), this
/// map stores the DefPathIndex (as it occurs in DefIdDirectory), so
/// that we can find the new DefId for a SerializedMetadataHash in a
/// subsequent compilation session.
///
/// This map is only needed for running auto-tests using the
/// #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes, and
/// is only populated if -Z query-dep-graph is specified. It will be
/// empty otherwise. Importing crates are perfectly happy with just having
/// the DefIndex.
pub
index_map
:
FnvHashMap
<
DefIndex
,
DefPathIndex
>
}
/// The hash for some metadata that (when saving) will be exported
...
...
src/librustc_incremental/persist/directory.rs
浏览文件 @
6a2666d5
...
...
@@ -178,7 +178,6 @@ pub fn lookup_def_path(&self, id: DefPathIndex) -> &DefPath {
&
self
.directory.paths
[
id
.index
as
usize
]
}
pub
fn
map
(
&
mut
self
,
node
:
&
DepNode
<
DefId
>
)
->
DepNode
<
DefPathIndex
>
{
node
.map_def
(|
&
def_id
|
Some
(
self
.add
(
def_id
)))
.unwrap
()
}
...
...
src/librustc_incremental/persist/dirty_clean.rs
浏览文件 @
6a2666d5
...
...
@@ -9,10 +9,10 @@
// except according to those terms.
//! Debugging code to test the state of the dependency graph just
//! after it is loaded from disk
. For each node marked with
//!
`#[rustc_clean]` or `#[rustc_dirty]`, we will check that a
//!
suitable node for that item either appears or does not appear in
//! the dep-graph, as appropriate:
//! after it is loaded from disk
and just after it has been saved.
//!
For each node marked with `#[rustc_clean]` or `#[rustc_dirty]`,
//!
we will check that a suitable node for that item either appears
//!
or does not appear in
the dep-graph, as appropriate:
//!
//! - `#[rustc_dirty(label="TypeckItemBody", cfg="rev2")]` if we are
//! in `#[cfg(rev2)]`, then there MUST NOT be a node
...
...
@@ -23,6 +23,22 @@
//!
//! Errors are reported if we are in the suitable configuration but
//! the required condition is not met.
//!
//! The `#[rustc_metadata_dirty]` and `#[rustc_metadata_clean]` attributes
//! can be used to check the incremental compilation hash (ICH) values of
//! metadata exported in rlibs.
//!
//! - If a node is marked with `#[rustc_metadata_clean(cfg="rev2")]` we
//! check that the metadata hash for that node is the same for "rev2"
//! it was for "rev1".
//! - If a node is marked with `#[rustc_metadata_dirty(cfg="rev2")]` we
//! check that the metadata hash for that node is *different* for "rev2"
//! than it was for "rev1".
//!
//! Note that the metadata-testing attributes must never specify the
//! first revision. This would lead to a crash since there is no
//! previous revision to compare things to.
//!
use
super
::
directory
::
RetracedDefIdDirectory
;
use
super
::
load
::
DirtyNodes
;
...
...
@@ -30,13 +46,14 @@
use
rustc
::
hir
;
use
rustc
::
hir
::
def_id
::
DefId
;
use
rustc
::
hir
::
intravisit
::
Visitor
;
use
rustc_data_structures
::
fnv
::
FnvHashSet
;
use
syntax
::
ast
::{
self
,
Attribute
,
NestedMetaItem
};
use
rustc_data_structures
::
fnv
::{
FnvHashSet
,
FnvHashMap
};
use
syntax
::
parse
::
token
::
InternedString
;
use
syntax_pos
::
Span
;
use
rustc
::
ty
::
TyCtxt
;
const
DIRTY
:
&
'static
str
=
"rustc_dirty"
;
const
CLEAN
:
&
'static
str
=
"rustc_clean"
;
use
{
ATTR_DIRTY
,
ATTR_CLEAN
,
ATTR_DIRTY_METADATA
,
ATTR_CLEAN_METADATA
}
;
const
LABEL
:
&
'static
str
=
"label"
;
const
CFG
:
&
'static
str
=
"cfg"
;
...
...
@@ -70,50 +87,11 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
}
impl
<
'a
,
'tcx
>
DirtyCleanVisitor
<
'a
,
'tcx
>
{
fn
expect_associated_value
(
&
self
,
item
:
&
NestedMetaItem
)
->
InternedString
{
if
let
Some
(
value
)
=
item
.value_str
()
{
value
}
else
{
let
msg
=
if
let
Some
(
name
)
=
item
.name
()
{
format!
(
"associated value expected for `{}`"
,
name
)
}
else
{
"expected an associated value"
.to_string
()
};
self
.tcx.sess
.span_fatal
(
item
.span
,
&
msg
);
}
}
/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
/// for a `cfg="foo"` attribute and check whether we have a cfg
/// flag called `foo`.
fn
check_config
(
&
self
,
attr
:
&
ast
::
Attribute
)
->
bool
{
debug!
(
"check_config(attr={:?})"
,
attr
);
let
config
=
&
self
.tcx.map
.krate
()
.config
;
debug!
(
"check_config: config={:?}"
,
config
);
for
item
in
attr
.meta_item_list
()
.unwrap_or
(
&
[])
{
if
item
.check_name
(
CFG
)
{
let
value
=
self
.expect_associated_value
(
item
);
debug!
(
"check_config: searching for cfg {:?}"
,
value
);
for
cfg
in
&
config
[
..
]
{
if
cfg
.check_name
(
&
value
[
..
])
{
debug!
(
"check_config: matched {:?}"
,
cfg
);
return
true
;
}
}
return
false
;
}
}
self
.tcx.sess
.span_fatal
(
attr
.span
,
&
format!
(
"no cfg attribute"
));
}
fn
dep_node
(
&
self
,
attr
:
&
Attribute
,
def_id
:
DefId
)
->
DepNode
<
DefId
>
{
for
item
in
attr
.meta_item_list
()
.unwrap_or
(
&
[])
{
if
item
.check_name
(
LABEL
)
{
let
value
=
self
.expect_associated_value
(
item
);
let
value
=
expect_associated_value
(
self
.tcx
,
item
);
match
DepNode
::
from_label_string
(
&
value
[
..
],
def_id
)
{
Ok
(
def_id
)
=>
return
def_id
,
Err
(())
=>
{
...
...
@@ -194,12 +172,12 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
fn
visit_item
(
&
mut
self
,
item
:
&
'tcx
hir
::
Item
)
{
let
def_id
=
self
.tcx.map
.local_def_id
(
item
.id
);
for
attr
in
self
.tcx
.get_attrs
(
def_id
)
.iter
()
{
if
attr
.check_name
(
DIRTY
)
{
if
self
.check_config
(
attr
)
{
if
attr
.check_name
(
ATTR_
DIRTY
)
{
if
check_config
(
self
.tcx
,
attr
)
{
self
.assert_dirty
(
item
,
self
.dep_node
(
attr
,
def_id
));
}
}
else
if
attr
.check_name
(
CLEAN
)
{
if
self
.check_config
(
attr
)
{
}
else
if
attr
.check_name
(
ATTR_
CLEAN
)
{
if
check_config
(
self
.tcx
,
attr
)
{
self
.assert_clean
(
item
,
self
.dep_node
(
attr
,
def_id
));
}
}
...
...
@@ -207,3 +185,115 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
}
}
pub
fn
check_dirty_clean_metadata
<
'a
,
'tcx
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
prev_metadata_hashes
:
&
FnvHashMap
<
DefId
,
u64
>
,
current_metadata_hashes
:
&
FnvHashMap
<
DefId
,
u64
>
)
{
if
!
tcx
.sess.opts.debugging_opts.query_dep_graph
{
return
;
}
tcx
.dep_graph
.with_ignore
(||{
let
krate
=
tcx
.map
.krate
();
krate
.visit_all_items
(
&
mut
DirtyCleanMetadataVisitor
{
tcx
:
tcx
,
prev_metadata_hashes
:
prev_metadata_hashes
,
current_metadata_hashes
:
current_metadata_hashes
,
});
});
}
pub
struct
DirtyCleanMetadataVisitor
<
'a
,
'tcx
:
'a
,
'm
>
{
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
prev_metadata_hashes
:
&
'm
FnvHashMap
<
DefId
,
u64
>
,
current_metadata_hashes
:
&
'm
FnvHashMap
<
DefId
,
u64
>
,
}
impl
<
'a
,
'tcx
,
'm
>
Visitor
<
'tcx
>
for
DirtyCleanMetadataVisitor
<
'a
,
'tcx
,
'm
>
{
fn
visit_item
(
&
mut
self
,
item
:
&
'tcx
hir
::
Item
)
{
let
def_id
=
self
.tcx.map
.local_def_id
(
item
.id
);
for
attr
in
self
.tcx
.get_attrs
(
def_id
)
.iter
()
{
if
attr
.check_name
(
ATTR_DIRTY_METADATA
)
{
if
check_config
(
self
.tcx
,
attr
)
{
self
.assert_state
(
false
,
def_id
,
item
.span
);
}
}
else
if
attr
.check_name
(
ATTR_CLEAN_METADATA
)
{
if
check_config
(
self
.tcx
,
attr
)
{
self
.assert_state
(
true
,
def_id
,
item
.span
);
}
}
}
}
}
impl
<
'a
,
'tcx
,
'm
>
DirtyCleanMetadataVisitor
<
'a
,
'tcx
,
'm
>
{
fn
assert_state
(
&
self
,
should_be_clean
:
bool
,
def_id
:
DefId
,
span
:
Span
)
{
let
item_path
=
self
.tcx
.item_path_str
(
def_id
);
debug!
(
"assert_state({})"
,
item_path
);
if
let
Some
(
&
prev_hash
)
=
self
.prev_metadata_hashes
.get
(
&
def_id
)
{
let
hashes_are_equal
=
prev_hash
==
self
.current_metadata_hashes
[
&
def_id
];
if
should_be_clean
&&
!
hashes_are_equal
{
self
.tcx.sess
.span_err
(
span
,
&
format!
(
"Metadata hash of `{}` is dirty, but should be clean"
,
item_path
));
}
let
should_be_dirty
=
!
should_be_clean
;
if
should_be_dirty
&&
hashes_are_equal
{
self
.tcx.sess
.span_err
(
span
,
&
format!
(
"Metadata hash of `{}` is clean, but should be dirty"
,
item_path
));
}
}
else
{
self
.tcx.sess
.span_err
(
span
,
&
format!
(
"Could not find previous metadata hash of `{}`"
,
item_path
));
}
}
}
/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
/// for a `cfg="foo"` attribute and check whether we have a cfg
/// flag called `foo`.
fn
check_config
(
tcx
:
TyCtxt
,
attr
:
&
ast
::
Attribute
)
->
bool
{
debug!
(
"check_config(attr={:?})"
,
attr
);
let
config
=
&
tcx
.map
.krate
()
.config
;
debug!
(
"check_config: config={:?}"
,
config
);
for
item
in
attr
.meta_item_list
()
.unwrap_or
(
&
[])
{
if
item
.check_name
(
CFG
)
{
let
value
=
expect_associated_value
(
tcx
,
item
);
debug!
(
"check_config: searching for cfg {:?}"
,
value
);
for
cfg
in
&
config
[
..
]
{
if
cfg
.check_name
(
&
value
[
..
])
{
debug!
(
"check_config: matched {:?}"
,
cfg
);
return
true
;
}
}
return
false
;
}
}
tcx
.sess
.span_fatal
(
attr
.span
,
&
format!
(
"no cfg attribute"
));
}
fn
expect_associated_value
(
tcx
:
TyCtxt
,
item
:
&
NestedMetaItem
)
->
InternedString
{
if
let
Some
(
value
)
=
item
.value_str
()
{
value
}
else
{
let
msg
=
if
let
Some
(
name
)
=
item
.name
()
{
format!
(
"associated value expected for `{}`"
,
name
)
}
else
{
"expected an associated value"
.to_string
()
};
tcx
.sess
.span_fatal
(
item
.span
,
&
msg
);
}
}
src/librustc_incremental/persist/load.rs
浏览文件 @
6a2666d5
...
...
@@ -12,9 +12,10 @@
use
rustc
::
dep_graph
::
DepNode
;
use
rustc
::
hir
::
def_id
::
DefId
;
use
rustc
::
hir
::
svh
::
Svh
;
use
rustc
::
session
::
Session
;
use
rustc
::
ty
::
TyCtxt
;
use
rustc_data_structures
::
fnv
::
FnvHashSet
;
use
rustc_data_structures
::
fnv
::
{
FnvHashSet
,
FnvHashMap
}
;
use
rustc_serialize
::
Decodable
as
RustcDecodable
;
use
rustc_serialize
::
opaque
::
Decoder
;
use
std
::
io
::
Read
;
...
...
@@ -224,6 +225,9 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
dirty_clean
::
check_dirty_clean_annotations
(
tcx
,
&
dirty_raw_source_nodes
,
&
retraced
);
load_prev_metadata_hashes
(
tcx
,
&
retraced
,
&
mut
*
incremental_hashes_map
.prev_metadata_hashes
.borrow_mut
());
Ok
(())
}
...
...
@@ -241,6 +245,9 @@ fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if
let
Some
(
dep_node
)
=
retraced
.map
(
&
hash
.dep_node
)
{
let
current_hash
=
hcx
.hash
(
&
dep_node
)
.unwrap
();
if
current_hash
==
hash
.hash
{
debug!
(
"initial_dirty_nodes: {:?} is clean (hash={:?})"
,
dep_node
.map_def
(|
&
def_id
|
Some
(
tcx
.def_path
(
def_id
)))
.unwrap
(),
current_hash
);
continue
;
}
debug!
(
"initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}"
,
...
...
@@ -304,3 +311,50 @@ fn delete_dirty_work_product(tcx: TyCtxt,
}
}
}
fn
load_prev_metadata_hashes
(
tcx
:
TyCtxt
,
retraced
:
&
RetracedDefIdDirectory
,
output
:
&
mut
FnvHashMap
<
DefId
,
u64
>
)
{
if
!
tcx
.sess.opts.debugging_opts.query_dep_graph
{
return
}
debug!
(
"load_prev_metadata_hashes() - Loading previous metadata hashes"
);
let
file_path
=
metadata_hash_export_path
(
tcx
.sess
);
if
!
file_path
.exists
()
{
debug!
(
"load_prev_metadata_hashes() - Couldn't find file containing
\
hashes at `{}`"
,
file_path
.display
());
return
}
debug!
(
"load_prev_metadata_hashes() - File: {}"
,
file_path
.display
());
let
mut
data
=
vec!
[];
if
!
File
::
open
(
&
file_path
)
.and_then
(|
mut
file
|
file
.read_to_end
(
&
mut
data
))
.is_ok
()
{
debug!
(
"load_prev_metadata_hashes() - Couldn't read file containing
\
hashes at `{}`"
,
file_path
.display
());
return
}
debug!
(
"load_prev_metadata_hashes() - Decoding hashes"
);
let
mut
decoder
=
Decoder
::
new
(
&
mut
data
,
0
);
let
_
=
Svh
::
decode
(
&
mut
decoder
)
.unwrap
();
let
serialized_hashes
=
SerializedMetadataHashes
::
decode
(
&
mut
decoder
)
.unwrap
();
debug!
(
"load_prev_metadata_hashes() - Mapping DefIds"
);
assert_eq!
(
serialized_hashes
.index_map
.len
(),
serialized_hashes
.hashes
.len
());
for
serialized_hash
in
serialized_hashes
.hashes
{
let
def_path_index
=
serialized_hashes
.index_map
[
&
serialized_hash
.def_index
];
if
let
Some
(
def_id
)
=
retraced
.def_id
(
def_path_index
)
{
let
old
=
output
.insert
(
def_id
,
serialized_hash
.hash
);
assert
!
(
old
.is_none
(),
"already have hash for {:?}"
,
def_id
);
}
}
debug!
(
"load_prev_metadata_hashes() - successfully loaded {} hashes"
,
serialized_hashes
.index_map
.len
());
}
src/librustc_incremental/persist/save.rs
浏览文件 @
6a2666d5
...
...
@@ -27,6 +27,7 @@
use
super
::
hash
::
*
;
use
super
::
preds
::
*
;
use
super
::
fs
::
*
;
use
super
::
dirty_clean
;
pub
fn
save_dep_graph
<
'a
,
'tcx
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
incremental_hashes_map
:
&
IncrementalHashesMap
,
...
...
@@ -37,16 +38,32 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if
sess
.opts.incremental
.is_none
()
{
return
;
}
let
mut
hcx
=
HashContext
::
new
(
tcx
,
incremental_hashes_map
);
let
mut
builder
=
DefIdDirectoryBuilder
::
new
(
tcx
);
let
query
=
tcx
.dep_graph
.query
();
let
mut
hcx
=
HashContext
::
new
(
tcx
,
incremental_hashes_map
);
let
preds
=
Predecessors
::
new
(
&
query
,
&
mut
hcx
);
let
mut
current_metadata_hashes
=
FnvHashMap
();
// IMPORTANT: We are saving the metadata hashes *before* the dep-graph,
// since metadata-encoding might add new entries to the
// DefIdDirectory (which is saved in the dep-graph file).
save_in
(
sess
,
metadata_hash_export_path
(
sess
),
|
e
|
encode_metadata_hashes
(
tcx
,
svh
,
&
preds
,
&
mut
builder
,
&
mut
current_metadata_hashes
,
e
));
save_in
(
sess
,
dep_graph_path
(
sess
),
|
e
|
encode_dep_graph
(
&
preds
,
&
mut
builder
,
e
));
save_in
(
sess
,
metadata_hash_export_path
(
sess
),
|
e
|
encode_metadata_hashes
(
tcx
,
svh
,
&
preds
,
&
mut
builder
,
e
));
let
prev_metadata_hashes
=
incremental_hashes_map
.prev_metadata_hashes
.borrow
();
dirty_clean
::
check_dirty_clean_metadata
(
tcx
,
&*
prev_metadata_hashes
,
&
current_metadata_hashes
);
}
pub
fn
save_work_products
(
sess
:
&
Session
)
{
...
...
@@ -63,13 +80,17 @@ pub fn save_work_products(sess: &Session) {
fn
save_in
<
F
>
(
sess
:
&
Session
,
path_buf
:
PathBuf
,
encode
:
F
)
where
F
:
FnOnce
(
&
mut
Encoder
)
->
io
::
Result
<
()
>
{
debug!
(
"save: storing data in {}"
,
path_buf
.display
());
// delete the old dep-graph, if any
// Note: It's important that we actually delete the old file and not just
// truncate and overwrite it, since it might be a shared hard-link, the
// underlying data of which we don't want to modify
if
path_buf
.exists
()
{
match
fs
::
remove_file
(
&
path_buf
)
{
Ok
(())
=>
{}
Ok
(())
=>
{
debug!
(
"save: remove old file"
);
}
Err
(
err
)
=>
{
sess
.err
(
&
format!
(
"unable to delete old dep-graph at `{}`: {}"
,
path_buf
.display
(),
...
...
@@ -94,7 +115,9 @@ fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
// write the data out
let
data
=
wr
.into_inner
();
match
File
::
create
(
&
path_buf
)
.and_then
(|
mut
file
|
file
.write_all
(
&
data
))
{
Ok
(
_
)
=>
{}
Ok
(
_
)
=>
{
debug!
(
"save: data written to disk successfully"
);
}
Err
(
err
)
=>
{
sess
.err
(
&
format!
(
"failed to write dep-graph to `{}`: {}"
,
path_buf
.display
(),
...
...
@@ -159,18 +182,9 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
svh
:
Svh
,
preds
:
&
Predecessors
,
builder
:
&
mut
DefIdDirectoryBuilder
,
current_metadata_hashes
:
&
mut
FnvHashMap
<
DefId
,
u64
>
,
encoder
:
&
mut
Encoder
)
->
io
::
Result
<
()
>
{
let
mut
def_id_hashes
=
FnvHashMap
();
let
mut
def_id_hash
=
|
def_id
:
DefId
|
->
u64
{
*
def_id_hashes
.entry
(
def_id
)
.or_insert_with
(||
{
let
index
=
builder
.add
(
def_id
);
let
path
=
builder
.lookup_def_path
(
index
);
path
.deterministic_hash
(
tcx
)
})
};
// For each `MetaData(X)` node where `X` is local, accumulate a
// hash. These are the metadata items we export. Downstream
// crates will want to see a hash that tells them whether we might
...
...
@@ -178,7 +192,13 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
// compiled.
//
// (I initially wrote this with an iterator, but it seemed harder to read.)
let
mut
serialized_hashes
=
SerializedMetadataHashes
{
hashes
:
vec!
[]
};
let
mut
serialized_hashes
=
SerializedMetadataHashes
{
hashes
:
vec!
[],
index_map
:
FnvHashMap
()
};
let
mut
def_id_hashes
=
FnvHashMap
();
for
(
&
target
,
sources
)
in
&
preds
.inputs
{
let
def_id
=
match
*
target
{
DepNode
::
MetaData
(
def_id
)
=>
{
...
...
@@ -188,6 +208,15 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
_
=>
continue
,
};
let
mut
def_id_hash
=
|
def_id
:
DefId
|
->
u64
{
*
def_id_hashes
.entry
(
def_id
)
.or_insert_with
(||
{
let
index
=
builder
.add
(
def_id
);
let
path
=
builder
.lookup_def_path
(
index
);
path
.deterministic_hash
(
tcx
)
})
};
// To create the hash for each item `X`, we don't hash the raw
// bytes of the metadata (though in principle we
// could). Instead, we walk the predecessors of `MetaData(X)`
...
...
@@ -221,6 +250,22 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
});
}
if
tcx
.sess.opts.debugging_opts.query_dep_graph
{
for
serialized_hash
in
&
serialized_hashes
.hashes
{
let
def_id
=
DefId
::
local
(
serialized_hash
.def_index
);
// Store entry in the index_map
let
def_path_index
=
builder
.add
(
def_id
);
serialized_hashes
.index_map
.insert
(
def_id
.index
,
def_path_index
);
// Record hash in current_metadata_hashes
current_metadata_hashes
.insert
(
def_id
,
serialized_hash
.hash
);
}
debug!
(
"save: stored index_map (len={}) for serialized hashes"
,
serialized_hashes
.index_map
.len
());
}
// Encode everything.
svh
.encode
(
encoder
)
?
;
serialized_hashes
.encode
(
encoder
)
?
;
...
...
src/libsyntax/feature_gate.rs
浏览文件 @
6a2666d5
...
...
@@ -508,6 +508,16 @@ fn f(features: &Features) -> bool {
is just used for rustc unit tests
\
and will never be stable"
,
cfg_fn!
(
rustc_attrs
))),
(
"rustc_metadata_dirty"
,
Whitelisted
,
Gated
(
"rustc_attrs"
,
"the `#[rustc_metadata_dirty]` attribute
\
is just used for rustc unit tests
\
and will never be stable"
,
cfg_fn!
(
rustc_attrs
))),
(
"rustc_metadata_clean"
,
Whitelisted
,
Gated
(
"rustc_attrs"
,
"the `#[rustc_metadata_clean]` attribute
\
is just used for rustc unit tests
\
and will never be stable"
,
cfg_fn!
(
rustc_attrs
))),
(
"rustc_partition_reused"
,
Whitelisted
,
Gated
(
"rustc_attrs"
,
"this attribute
\
is just used for rustc unit tests
\
...
...
src/test/incremental/hashes/struct_defs.rs
0 → 100644
浏览文件 @
6a2666d5
// Copyright 2016 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.
// This test case tests the incremental compilation hash (ICH) implementation
// for struct definitions.
// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.
// We also test the ICH for struct definitions exported in metadata. Same as
// above, we want to make sure that the change between rev1 and rev2 also
// results in a change of the ICH for the struct's metadata, and that it stays
// the same between rev2 and rev3.
// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph
#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type=
"rlib"
]
// Layout ----------------------------------------------------------------------
#[cfg(cfail1)]
pub
struct
LayoutPacked
;
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
#[repr(packed)]
pub
struct
LayoutPacked
;
#[cfg(cfail1)]
struct
LayoutC
;
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
#[repr(C)]
struct
LayoutC
;
// Tuple Struct Change Field Type ----------------------------------------------
#[cfg(cfail1)]
struct
TupleStructFieldType
(
i32
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
TupleStructFieldType
(
u32
);
// Tuple Struct Add Field ------------------------------------------------------
#[cfg(cfail1)]
struct
TupleStructAddField
(
i32
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
TupleStructAddField
(
i32
,
u32
);
// Tuple Struct Field Visibility -----------------------------------------------
#[cfg(cfail1)]
struct
TupleStructFieldVisibility
(
char
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
TupleStructFieldVisibility
(
pub
char
);
// Record Struct Field Type ----------------------------------------------------
#[cfg(cfail1)]
struct
RecordStructFieldType
{
x
:
f32
}
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
RecordStructFieldType
{
x
:
u64
}
// Record Struct Field Name ----------------------------------------------------
#[cfg(cfail1)]
struct
RecordStructFieldName
{
x
:
f32
}
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
RecordStructFieldName
{
y
:
f32
}
// Record Struct Add Field -----------------------------------------------------
#[cfg(cfail1)]
struct
RecordStructAddField
{
x
:
f32
}
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
RecordStructAddField
{
x
:
f32
,
y
:
()
}
// Record Struct Field Visibility ----------------------------------------------
#[cfg(cfail1)]
struct
RecordStructFieldVisibility
{
x
:
f32
}
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
RecordStructFieldVisibility
{
pub
x
:
f32
}
// Add Lifetime Parameter ------------------------------------------------------
#[cfg(cfail1)]
struct
AddLifetimeParameter
<
'a
>
(
&
'a
f32
,
&
'a
f64
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
AddLifetimeParameter
<
'a
,
'b
>
(
&
'a
f32
,
&
'b
f64
);
// Add Lifetime Parameter Bound ------------------------------------------------
#[cfg(cfail1)]
struct
AddLifetimeParameterBound
<
'a
,
'b
>
(
&
'a
f32
,
&
'b
f64
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
AddLifetimeParameterBound
<
'a
,
'b
:
'a
>
(
&
'a
f32
,
&
'b
f64
);
#[cfg(cfail1)]
struct
AddLifetimeParameterBoundWhereClause
<
'a
,
'b
>
(
&
'a
f32
,
&
'b
f64
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
AddLifetimeParameterBoundWhereClause
<
'a
,
'b
>
(
&
'a
f32
,
&
'b
f64
)
where
'b
:
'a
;
// Add Type Parameter ----------------------------------------------------------
#[cfg(cfail1)]
struct
AddTypeParameter
<
T1
>
(
T1
,
T1
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
AddTypeParameter
<
T1
,
T2
>
(
T1
,
T2
);
// Add Type Parameter Bound ----------------------------------------------------
#[cfg(cfail1)]
struct
AddTypeParameterBound
<
T
>
(
T
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
AddTypeParameterBound
<
T
:
Send
>
(
T
);
#[cfg(cfail1)]
struct
AddTypeParameterBoundWhereClause
<
T
>
(
T
);
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_dirty(cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
struct
AddTypeParameterBoundWhereClause
<
T
>
(
T
)
where
T
:
Sync
;
// Empty struct ----------------------------------------------------------------
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_metadata_clean(cfg=
"cfail2"
)]
pub
struct
EmptyStruct
;
// Visibility ------------------------------------------------------------------
#[cfg(cfail1)]
struct
Visibility
;
#[cfg(not(cfail1))]
#[rustc_dirty(label=
"Hir"
,
cfg=
"cfail2"
)]
#[rustc_clean(label=
"Hir"
,
cfg=
"cfail3"
)]
#[rustc_metadata_clean(cfg=
"cfail3"
)]
pub
struct
Visibility
;
src/tools/compiletest/src/header.rs
浏览文件 @
6a2666d5
...
...
@@ -182,42 +182,32 @@ pub struct TestProps {
// testing harness and used when generating compilation
// arguments. (In particular, it propagates to the aux-builds.)
pub
incremental_dir
:
Option
<
PathBuf
>
,
// Specifies that a cfail test must actually compile without errors.
pub
must_compile_successfully
:
bool
,
}
impl
TestProps
{
pub
fn
new
()
->
Self
{
let
error_patterns
=
Vec
::
new
();
let
aux_builds
=
Vec
::
new
();
let
exec_env
=
Vec
::
new
();
let
run_flags
=
None
;
let
pp_exact
=
None
;
let
check_lines
=
Vec
::
new
();
let
build_aux_docs
=
false
;
let
force_host
=
false
;
let
check_stdout
=
false
;
let
no_prefer_dynamic
=
false
;
let
pretty_expanded
=
false
;
let
pretty_compare_only
=
false
;
let
forbid_output
=
Vec
::
new
();
TestProps
{
error_patterns
:
error_patterns
,
error_patterns
:
vec!
[]
,
compile_flags
:
vec!
[],
run_flags
:
run_flags
,
pp_exact
:
pp_exact
,
aux_builds
:
aux_builds
,
run_flags
:
None
,
pp_exact
:
None
,
aux_builds
:
vec!
[]
,
revisions
:
vec!
[],
rustc_env
:
vec!
[],
exec_env
:
exec_env
,
check_lines
:
check_lines
,
build_aux_docs
:
build_aux_docs
,
force_host
:
f
orce_host
,
check_stdout
:
check_stdout
,
no_prefer_dynamic
:
no_prefer_dynamic
,
pretty_expanded
:
pretty_expanded
,
exec_env
:
vec!
[]
,
check_lines
:
vec!
[]
,
build_aux_docs
:
false
,
force_host
:
f
alse
,
check_stdout
:
false
,
no_prefer_dynamic
:
false
,
pretty_expanded
:
false
,
pretty_mode
:
format!
(
"normal"
),
pretty_compare_only
:
pretty_compare_only
,
forbid_output
:
forbid_output
,
pretty_compare_only
:
false
,
forbid_output
:
vec!
[]
,
incremental_dir
:
None
,
must_compile_successfully
:
false
,
}
}
...
...
@@ -313,6 +303,10 @@ pub fn load_from(&mut self, testfile: &Path, cfg: Option<&str>) {
if
let
Some
(
of
)
=
parse_forbid_output
(
ln
)
{
self
.forbid_output
.push
(
of
);
}
if
!
self
.must_compile_successfully
{
self
.must_compile_successfully
=
parse_must_compile_successfully
(
ln
);
}
});
for
key
in
vec!
[
"RUST_TEST_NOCAPTURE"
,
"RUST_TEST_THREADS"
]
{
...
...
@@ -420,6 +414,10 @@ fn parse_pretty_compare_only(line: &str) -> bool {
parse_name_directive
(
line
,
"pretty-compare-only"
)
}
fn
parse_must_compile_successfully
(
line
:
&
str
)
->
bool
{
parse_name_directive
(
line
,
"must-compile-successfully"
)
}
fn
parse_env
(
line
:
&
str
,
name
:
&
str
)
->
Option
<
(
String
,
String
)
>
{
parse_name_value_directive
(
line
,
name
)
.map
(|
nv
|
{
// nv is either FOO or FOO=BAR
...
...
src/tools/compiletest/src/runtest.rs
浏览文件 @
6a2666d5
...
...
@@ -129,6 +129,13 @@ fn complete_all(&self) {
fn
run_cfail_test
(
&
self
)
{
let
proc_res
=
self
.compile_test
();
if
self
.props.must_compile_successfully
{
if
!
proc_res
.status
.success
()
{
self
.fatal_proc_rec
(
"test compilation failed although it shouldn't!"
,
&
proc_res
);
}
}
else
{
if
proc_res
.status
.success
()
{
self
.fatal_proc_rec
(
&
format!
(
"{} test compiled successfully!"
,
self
.config.mode
)[
..
],
...
...
@@ -136,6 +143,7 @@ fn run_cfail_test(&self) {
}
self
.check_correct_failure_status
(
&
proc_res
);
}
let
output_to_check
=
self
.get_output
(
&
proc_res
);
let
expected_errors
=
errors
::
load_errors
(
&
self
.testpaths.file
,
self
.revision
);
...
...
@@ -147,6 +155,7 @@ fn run_cfail_test(&self) {
}
else
{
self
.check_error_patterns
(
&
output_to_check
,
&
proc_res
);
}
self
.check_no_compiler_crash
(
&
proc_res
);
self
.check_forbid_output
(
&
output_to_check
,
&
proc_res
);
}
...
...
@@ -943,9 +952,13 @@ fn check_error_patterns(&self,
output_to_check
:
&
str
,
proc_res
:
&
ProcRes
)
{
if
self
.props.error_patterns
.is_empty
()
{
if
self
.props.must_compile_successfully
{
return
}
else
{
self
.fatal
(
&
format!
(
"no error pattern specified in {:?}"
,
self
.testpaths.file
.display
()));
}
}
let
mut
next_err_idx
=
0
;
let
mut
next_err_pat
=
self
.props.error_patterns
[
next_err_idx
]
.trim
();
let
mut
done
=
false
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录