Skip to content

Commit a3f990d

Browse files
committed
Auto merge of #45472 - michaelwoerister:incr-comp-caching-base, r=nikomatsakis
incr.comp.: Implement compiler diagnostic persistence. This PR implements storing and loading diagnostics that the compiler generates and thus allows for emitting warnings during incremental compilation without actually re-evaluating the thing the warning originally came from. It also lays some groundwork for storing and loading type information and MIR in the incr. comp. cache. ~~It is still work in progress:~~ - ~~There's still some documentation to be added.~~ - ~~The way anonymous queries are handled might lead to duplicated emissions of warnings. Not sure if there is a better way or how frequent such duplication would be in practice.~~ Diagnostic message duplication is addressed separately in #45519. r? @nikomatsakis
2 parents 2f581cf + 6faba5b commit a3f990d

File tree

22 files changed

+707
-150
lines changed

22 files changed

+707
-150
lines changed

src/librustc/dep_graph/graph.rs

+19
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use errors::DiagnosticBuilder;
1112
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
1213
StableHashingContextProvider};
1314
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -600,6 +601,24 @@ impl DepGraph {
600601
"DepGraph::try_mark_green() - Duplicate fingerprint \
601602
insertion for {:?}", dep_node);
602603

604+
// ... emitting any stored diagnostic ...
605+
{
606+
let diagnostics = tcx.on_disk_query_result_cache
607+
.load_diagnostics(prev_dep_node_index);
608+
609+
if diagnostics.len() > 0 {
610+
let handle = tcx.sess.diagnostic();
611+
612+
// Promote the previous diagnostics to the current session.
613+
tcx.on_disk_query_result_cache
614+
.store_diagnostics(dep_node_index, diagnostics.clone());
615+
616+
for diagnostic in diagnostics {
617+
DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit();
618+
}
619+
}
620+
}
621+
603622
// ... and finally storing a "Green" entry in the color map.
604623
let old_color = data.colors
605624
.borrow_mut()

src/librustc/dep_graph/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ pub use self::prev::PreviousDepGraph;
2626
pub use self::query::DepGraphQuery;
2727
pub use self::safe::AssertDepGraphSafe;
2828
pub use self::safe::DepGraphSafe;
29-
pub use self::serialized::SerializedDepGraph;
29+
pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex};

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#![feature(const_fn)]
4747
#![feature(core_intrinsics)]
4848
#![feature(i128_type)]
49+
#![feature(inclusive_range_syntax)]
4950
#![cfg_attr(windows, feature(libc))]
5051
#![feature(macro_vis_matcher)]
5152
#![feature(never_type)]

src/librustc/ty/codec.rs

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
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+
11+
// This module contains some shared code for encoding and decoding various
12+
// things from the `ty` module, and in particular implements support for
13+
// "shorthands" which allow to have pointers back into the already encoded
14+
// stream instead of re-encoding the same thing twice.
15+
//
16+
// The functionality in here is shared between persisting to crate metadata and
17+
// persisting to incr. comp. caches.
18+
19+
use hir::def_id::{DefId, CrateNum};
20+
use middle::const_val::ByteArray;
21+
use rustc_data_structures::fx::FxHashMap;
22+
use rustc_serialize::{Decodable, Decoder, Encoder, Encodable};
23+
use std::hash::Hash;
24+
use std::intrinsics;
25+
use ty::{self, Ty, TyCtxt};
26+
use ty::subst::Substs;
27+
28+
/// The shorthand encoding uses an enum's variant index `usize`
29+
/// and is offset by this value so it never matches a real variant.
30+
/// This offset is also chosen so that the first byte is never < 0x80.
31+
pub const SHORTHAND_OFFSET: usize = 0x80;
32+
33+
pub trait EncodableWithShorthand: Clone + Eq + Hash {
34+
type Variant: Encodable;
35+
fn variant(&self) -> &Self::Variant;
36+
}
37+
38+
impl<'tcx> EncodableWithShorthand for Ty<'tcx> {
39+
type Variant = ty::TypeVariants<'tcx>;
40+
fn variant(&self) -> &Self::Variant {
41+
&self.sty
42+
}
43+
}
44+
45+
impl<'tcx> EncodableWithShorthand for ty::Predicate<'tcx> {
46+
type Variant = ty::Predicate<'tcx>;
47+
fn variant(&self) -> &Self::Variant {
48+
self
49+
}
50+
}
51+
52+
pub trait TyEncoder: Encoder {
53+
fn position(&self) -> usize;
54+
}
55+
56+
/// Encode the given value or a previously cached shorthand.
57+
pub fn encode_with_shorthand<E, T, M>(encoder: &mut E,
58+
value: &T,
59+
cache: M)
60+
-> Result<(), E::Error>
61+
where E: TyEncoder,
62+
M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
63+
T: EncodableWithShorthand,
64+
{
65+
let existing_shorthand = cache(encoder).get(value).cloned();
66+
if let Some(shorthand) = existing_shorthand {
67+
return encoder.emit_usize(shorthand);
68+
}
69+
70+
let variant = value.variant();
71+
72+
let start = encoder.position();
73+
variant.encode(encoder)?;
74+
let len = encoder.position() - start;
75+
76+
// The shorthand encoding uses the same usize as the
77+
// discriminant, with an offset so they can't conflict.
78+
let discriminant = unsafe { intrinsics::discriminant_value(variant) };
79+
assert!(discriminant < SHORTHAND_OFFSET as u64);
80+
let shorthand = start + SHORTHAND_OFFSET;
81+
82+
// Get the number of bits that leb128 could fit
83+
// in the same space as the fully encoded type.
84+
let leb128_bits = len * 7;
85+
86+
// Check that the shorthand is a not longer than the
87+
// full encoding itself, i.e. it's an obvious win.
88+
if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) {
89+
cache(encoder).insert(value.clone(), shorthand);
90+
}
91+
92+
Ok(())
93+
}
94+
95+
pub fn encode_predicates<'tcx, E, C>(encoder: &mut E,
96+
predicates: &ty::GenericPredicates<'tcx>,
97+
cache: C)
98+
-> Result<(), E::Error>
99+
where E: TyEncoder,
100+
C: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<ty::Predicate<'tcx>, usize>,
101+
{
102+
predicates.parent.encode(encoder)?;
103+
predicates.predicates.len().encode(encoder)?;
104+
for predicate in &predicates.predicates {
105+
encode_with_shorthand(encoder, predicate, &cache)?
106+
}
107+
Ok(())
108+
}
109+
110+
pub trait TyDecoder<'a, 'tcx: 'a>: Decoder {
111+
112+
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
113+
114+
fn peek_byte(&self) -> u8;
115+
116+
fn cached_ty_for_shorthand<F>(&mut self,
117+
shorthand: usize,
118+
or_insert_with: F)
119+
-> Result<Ty<'tcx>, Self::Error>
120+
where F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>;
121+
122+
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
123+
where F: FnOnce(&mut Self) -> R;
124+
125+
fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum;
126+
127+
fn positioned_at_shorthand(&self) -> bool {
128+
(self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
129+
}
130+
}
131+
132+
pub fn decode_cnum<'a, 'tcx, D>(decoder: &mut D) -> Result<CrateNum, D::Error>
133+
where D: TyDecoder<'a, 'tcx>,
134+
'tcx: 'a,
135+
{
136+
let cnum = CrateNum::from_u32(u32::decode(decoder)?);
137+
Ok(decoder.map_encoded_cnum_to_current(cnum))
138+
}
139+
140+
pub fn decode_ty<'a, 'tcx, D>(decoder: &mut D) -> Result<Ty<'tcx>, D::Error>
141+
where D: TyDecoder<'a, 'tcx>,
142+
'tcx: 'a,
143+
{
144+
// Handle shorthands first, if we have an usize > 0x80.
145+
// if self.opaque.data[self.opaque.position()] & 0x80 != 0 {
146+
if decoder.positioned_at_shorthand() {
147+
let pos = decoder.read_usize()?;
148+
assert!(pos >= SHORTHAND_OFFSET);
149+
let shorthand = pos - SHORTHAND_OFFSET;
150+
151+
decoder.cached_ty_for_shorthand(shorthand, |decoder| {
152+
decoder.with_position(shorthand, Ty::decode)
153+
})
154+
} else {
155+
let tcx = decoder.tcx();
156+
Ok(tcx.mk_ty(ty::TypeVariants::decode(decoder)?))
157+
}
158+
}
159+
160+
pub fn decode_predicates<'a, 'tcx, D>(decoder: &mut D)
161+
-> Result<ty::GenericPredicates<'tcx>, D::Error>
162+
where D: TyDecoder<'a, 'tcx>,
163+
'tcx: 'a,
164+
{
165+
Ok(ty::GenericPredicates {
166+
parent: Decodable::decode(decoder)?,
167+
predicates: (0..decoder.read_usize()?).map(|_| {
168+
// Handle shorthands first, if we have an usize > 0x80.
169+
if decoder.positioned_at_shorthand() {
170+
let pos = decoder.read_usize()?;
171+
assert!(pos >= SHORTHAND_OFFSET);
172+
let shorthand = pos - SHORTHAND_OFFSET;
173+
174+
decoder.with_position(shorthand, ty::Predicate::decode)
175+
} else {
176+
ty::Predicate::decode(decoder)
177+
}
178+
})
179+
.collect::<Result<Vec<_>, _>>()?,
180+
})
181+
}
182+
183+
pub fn decode_substs<'a, 'tcx, D>(decoder: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error>
184+
where D: TyDecoder<'a, 'tcx>,
185+
'tcx: 'a,
186+
{
187+
let len = decoder.read_usize()?;
188+
let tcx = decoder.tcx();
189+
Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
190+
}
191+
192+
pub fn decode_region<'a, 'tcx, D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error>
193+
where D: TyDecoder<'a, 'tcx>,
194+
'tcx: 'a,
195+
{
196+
Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?))
197+
}
198+
199+
pub fn decode_ty_slice<'a, 'tcx, D>(decoder: &mut D)
200+
-> Result<&'tcx ty::Slice<Ty<'tcx>>, D::Error>
201+
where D: TyDecoder<'a, 'tcx>,
202+
'tcx: 'a,
203+
{
204+
let len = decoder.read_usize()?;
205+
Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?)
206+
}
207+
208+
pub fn decode_adt_def<'a, 'tcx, D>(decoder: &mut D)
209+
-> Result<&'tcx ty::AdtDef, D::Error>
210+
where D: TyDecoder<'a, 'tcx>,
211+
'tcx: 'a,
212+
{
213+
let def_id = DefId::decode(decoder)?;
214+
Ok(decoder.tcx().adt_def(def_id))
215+
}
216+
217+
pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D)
218+
-> Result<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, D::Error>
219+
where D: TyDecoder<'a, 'tcx>,
220+
'tcx: 'a,
221+
{
222+
let len = decoder.read_usize()?;
223+
Ok(decoder.tcx()
224+
.mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
225+
}
226+
227+
pub fn decode_byte_array<'a, 'tcx, D>(decoder: &mut D)
228+
-> Result<ByteArray<'tcx>, D::Error>
229+
where D: TyDecoder<'a, 'tcx>,
230+
'tcx: 'a,
231+
{
232+
Ok(ByteArray {
233+
data: decoder.tcx().alloc_byte_array(&Vec::decode(decoder)?)
234+
})
235+
}
236+
237+
pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
238+
-> Result<&'tcx ty::Const<'tcx>, D::Error>
239+
where D: TyDecoder<'a, 'tcx>,
240+
'tcx: 'a,
241+
{
242+
Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
243+
}

src/librustc/ty/context.rs

+16
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,11 @@ pub struct GlobalCtxt<'tcx> {
855855

856856
pub dep_graph: DepGraph,
857857

858+
/// This provides access to the incr. comp. on-disk cache for query results.
859+
/// Do not access this directly. It is only meant to be used by
860+
/// `DepGraph::try_mark_green()` and the query infrastructure in `ty::maps`.
861+
pub(crate) on_disk_query_result_cache: maps::OnDiskCache<'tcx>,
862+
858863
/// Common types, pre-interned for your convenience.
859864
pub types: CommonTypes<'tcx>,
860865

@@ -1056,6 +1061,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
10561061
resolutions: ty::Resolutions,
10571062
named_region_map: resolve_lifetime::NamedRegionMap,
10581063
hir: hir_map::Map<'tcx>,
1064+
on_disk_query_result_cache: maps::OnDiskCache<'tcx>,
10591065
crate_name: &str,
10601066
tx: mpsc::Sender<Box<Any + Send>>,
10611067
output_filenames: &OutputFilenames,
@@ -1139,6 +1145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
11391145
global_arenas: arenas,
11401146
global_interners: interners,
11411147
dep_graph: dep_graph.clone(),
1148+
on_disk_query_result_cache,
11421149
types: common_types,
11431150
named_region_map: NamedRegionMap {
11441151
defs,
@@ -1300,6 +1307,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
13001307
self.in_scope_traits_map(def_index);
13011308
}
13021309
}
1310+
1311+
pub fn serialize_query_result_cache<E>(self,
1312+
encoder: &mut E)
1313+
-> Result<(), E::Error>
1314+
where E: ::rustc_serialize::Encoder
1315+
{
1316+
self.on_disk_query_result_cache.serialize(encoder)
1317+
}
1318+
13031319
}
13041320

13051321
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {

src/librustc/ty/maps/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ mod config;
7070
pub use self::config::QueryConfig;
7171
use self::config::QueryDescription;
7272

73+
mod on_disk_cache;
74+
pub use self::on_disk_cache::OnDiskCache;
75+
7376
// Each of these maps also corresponds to a method on a
7477
// `Provider` trait for requesting a value of that type,
7578
// and a method on `Maps` itself for doing that in a

0 commit comments

Comments
 (0)