]> git.proxmox.com Git - rustc.git/blame - src/librustc_metadata/isolated_encoder.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / librustc_metadata / isolated_encoder.rs
CommitLineData
7cac9316
XL
1// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use encoder::EncodeContext;
12use schema::{Lazy, LazySeq};
13
14use rustc::ich::{StableHashingContext, Fingerprint};
15use rustc::ty::TyCtxt;
16
17use rustc_data_structures::accumulate_vec::AccumulateVec;
18use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
19use rustc_serialize::Encodable;
20
21/// The IsolatedEncoder provides facilities to write to crate metadata while
22/// making sure that anything going through it is also feed into an ICH hasher.
23pub struct IsolatedEncoder<'a, 'b: 'a, 'tcx: 'b> {
24 pub tcx: TyCtxt<'b, 'tcx, 'tcx>,
25 ecx: &'a mut EncodeContext<'b, 'tcx>,
ea8adc8c 26 hcx: Option<(StableHashingContext<'tcx>, StableHasher<Fingerprint>)>,
7cac9316
XL
27}
28
29impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
30
31 pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self {
32 let tcx = ecx.tcx;
33 let compute_ich = ecx.compute_ich;
34 IsolatedEncoder {
3b2f2976
XL
35 tcx,
36 ecx,
7cac9316
XL
37 hcx: if compute_ich {
38 // We are always hashing spans for things in metadata because
39 // don't know if a downstream crate will use them or not.
40 // Except when -Zquery-dep-graph is specified because we don't
41 // want to mess up our tests.
42 let hcx = if tcx.sess.opts.debugging_opts.query_dep_graph {
ea8adc8c 43 tcx.create_stable_hashing_context()
7cac9316 44 } else {
ea8adc8c 45 tcx.create_stable_hashing_context().force_span_hashing()
7cac9316
XL
46 };
47
48 Some((hcx, StableHasher::new()))
49 } else {
50 None
51 }
52 }
53 }
54
55 pub fn finish(self) -> (Option<Fingerprint>, &'a mut EncodeContext<'b, 'tcx>) {
56 if let Some((_, hasher)) = self.hcx {
57 (Some(hasher.finish()), self.ecx)
58 } else {
59 (None, self.ecx)
60 }
61 }
62
63 pub fn lazy<T>(&mut self, value: &T) -> Lazy<T>
ea8adc8c 64 where T: Encodable + HashStable<StableHashingContext<'tcx>>
7cac9316
XL
65 {
66 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
67 value.hash_stable(hcx, hasher);
68 debug!("metadata-hash: {:?}", hasher);
69 }
70 self.ecx.lazy(value)
71 }
72
73 pub fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
74 where I: IntoIterator<Item = T>,
ea8adc8c 75 T: Encodable + HashStable<StableHashingContext<'tcx>>
7cac9316
XL
76 {
77 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
78 let iter = iter.into_iter();
79 let (lower_bound, upper_bound) = iter.size_hint();
80
81 if upper_bound == Some(lower_bound) {
82 lower_bound.hash_stable(hcx, hasher);
83 let mut num_items_hashed = 0;
84 let ret = self.ecx.lazy_seq(iter.inspect(|item| {
85 item.hash_stable(hcx, hasher);
86 num_items_hashed += 1;
87 }));
88
89 // Sometimes items in a sequence are filtered out without being
90 // hashed (e.g. for &[ast::Attribute]) and this code path cannot
91 // handle that correctly, so we want to make sure we didn't hit
92 // it by accident.
93 if lower_bound != num_items_hashed {
94 bug!("Hashed a different number of items ({}) than expected ({})",
95 num_items_hashed,
96 lower_bound);
97 }
98 debug!("metadata-hash: {:?}", hasher);
99 ret
100 } else {
101 // Collect into a vec so we know the length of the sequence
102 let items: AccumulateVec<[T; 32]> = iter.collect();
103 items.hash_stable(hcx, hasher);
104 debug!("metadata-hash: {:?}", hasher);
105 self.ecx.lazy_seq(items)
106 }
107 } else {
108 self.ecx.lazy_seq(iter)
109 }
110 }
111
112 pub fn lazy_seq_ref<'x, I, T>(&mut self, iter: I) -> LazySeq<T>
113 where I: IntoIterator<Item = &'x T>,
ea8adc8c 114 T: 'x + Encodable + HashStable<StableHashingContext<'tcx>>
7cac9316
XL
115 {
116 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
117 let iter = iter.into_iter();
118 let (lower_bound, upper_bound) = iter.size_hint();
119
120 if upper_bound == Some(lower_bound) {
121 lower_bound.hash_stable(hcx, hasher);
122 let mut num_items_hashed = 0;
123 let ret = self.ecx.lazy_seq_ref(iter.inspect(|item| {
124 item.hash_stable(hcx, hasher);
125 num_items_hashed += 1;
126 }));
127
128 // Sometimes items in a sequence are filtered out without being
129 // hashed (e.g. for &[ast::Attribute]) and this code path cannot
130 // handle that correctly, so we want to make sure we didn't hit
131 // it by accident.
132 if lower_bound != num_items_hashed {
133 bug!("Hashed a different number of items ({}) than expected ({})",
134 num_items_hashed,
135 lower_bound);
136 }
137 debug!("metadata-hash: {:?}", hasher);
138 ret
139 } else {
140 // Collect into a vec so we know the length of the sequence
141 let items: AccumulateVec<[&'x T; 32]> = iter.collect();
142 items.hash_stable(hcx, hasher);
143 debug!("metadata-hash: {:?}", hasher);
144 self.ecx.lazy_seq_ref(items.iter().map(|x| *x))
145 }
146 } else {
147 self.ecx.lazy_seq_ref(iter)
148 }
149 }
150
151 pub fn lazy_seq_from_slice<T>(&mut self, slice: &[T]) -> LazySeq<T>
ea8adc8c 152 where T: Encodable + HashStable<StableHashingContext<'tcx>>
7cac9316
XL
153 {
154 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
155 slice.hash_stable(hcx, hasher);
156 debug!("metadata-hash: {:?}", hasher);
157 }
158 self.ecx.lazy_seq_ref(slice.iter())
159 }
160
161 pub fn lazy_seq_ref_from_slice<T>(&mut self, slice: &[&T]) -> LazySeq<T>
ea8adc8c 162 where T: Encodable + HashStable<StableHashingContext<'tcx>>
7cac9316
XL
163 {
164 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
165 slice.hash_stable(hcx, hasher);
166 debug!("metadata-hash: {:?}", hasher);
167 }
168 self.ecx.lazy_seq_ref(slice.iter().map(|x| *x))
169 }
170}