Skip to content

Commit df1e12f

Browse files
committed
Call FileEncoder::finish in rmeta encoding
1 parent d4c86cf commit df1e12f

File tree

14 files changed

+87
-45
lines changed

14 files changed

+87
-45
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4105,6 +4105,7 @@ dependencies = [
41054105
"rustc_query_impl",
41064106
"rustc_query_system",
41074107
"rustc_resolve",
4108+
"rustc_serialize",
41084109
"rustc_session",
41094110
"rustc_span",
41104111
"rustc_symbol_mangling",

compiler/rustc_codegen_ssa/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ impl CodegenResults {
226226
encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());
227227
encoder.emit_str(sess.cfg_version);
228228
Encodable::encode(codegen_results, &mut encoder);
229-
encoder.finish()
229+
encoder.finish().map_err(|(_path, err)| err)
230230
}
231231

232232
pub fn deserialize_rlink(sess: &Session, data: Vec<u8>) -> Result<Self, CodegenErrors> {

compiler/rustc_incremental/src/persist/file_format.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ where
8080
);
8181
debug!("save: data written to disk successfully");
8282
}
83-
Err(err) => {
84-
sess.emit_err(errors::WriteNew { name, path: path_buf, err });
83+
Err((path, err)) => {
84+
sess.emit_err(errors::WriteNew { name, path, err });
8585
}
8686
}
8787
}

compiler/rustc_incremental/src/persist/save.rs

-3
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
5050
join(
5151
move || {
5252
sess.time("incr_comp_persist_dep_graph", || {
53-
if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) {
54-
sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err });
55-
}
5653
if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
5754
sess.emit_err(errors::MoveDepGraph {
5855
from: &staging_dep_graph_path,

compiler/rustc_interface/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ rustc_privacy = { path = "../rustc_privacy" }
4040
rustc_query_impl = { path = "../rustc_query_impl" }
4141
rustc_query_system = { path = "../rustc_query_system" }
4242
rustc_resolve = { path = "../rustc_resolve" }
43+
rustc_serialize = { path = "../rustc_serialize" }
4344
rustc_session = { path = "../rustc_session" }
4445
rustc_span = { path = "../rustc_span" }
4546
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }

compiler/rustc_interface/src/queries.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation};
22
use crate::interface::{Compiler, Result};
3-
use crate::{passes, util};
3+
use crate::{errors, passes, util};
44

55
use rustc_ast as ast;
66
use rustc_codegen_ssa::traits::CodegenBackend;
@@ -15,6 +15,7 @@ use rustc_metadata::creader::CStore;
1515
use rustc_middle::arena::Arena;
1616
use rustc_middle::dep_graph::DepGraph;
1717
use rustc_middle::ty::{GlobalCtxt, TyCtxt};
18+
use rustc_serialize::opaque::FileEncodeResult;
1819
use rustc_session::config::{self, CrateType, OutputFilenames, OutputType};
1920
use rustc_session::cstore::Untracked;
2021
use rustc_session::{output::find_crate_name, Session};
@@ -101,6 +102,10 @@ impl<'tcx> Queries<'tcx> {
101102
}
102103
}
103104

105+
pub fn finish(&self) -> FileEncodeResult {
106+
if let Some(gcx) = self.gcx_cell.get() { gcx.finish() } else { Ok(0) }
107+
}
108+
104109
fn session(&self) -> &Lrc<Session> {
105110
&self.compiler.sess
106111
}
@@ -345,6 +350,10 @@ impl Compiler {
345350
.time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph));
346351
}
347352

353+
if let Err((path, error)) = queries.finish() {
354+
self.session().emit_err(errors::FailedWritingFile { path: &path, error });
355+
}
356+
348357
_timer = Some(self.session().timer("free_global_ctxt"));
349358

350359
ret

compiler/rustc_metadata/messages.ftl

+1-4
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,8 @@ metadata_extern_location_not_file =
6363
metadata_fail_create_file_encoder =
6464
failed to create file encoder: {$err}
6565
66-
metadata_fail_seek_file =
67-
failed to seek the file: {$err}
68-
6966
metadata_fail_write_file =
70-
failed to write to the file: {$err}
67+
failed to write to `{$path}`: {$err}
7168
7269
metadata_failed_copy_to_stdout =
7370
failed to copy {$filename} to stdout: {$err}

compiler/rustc_metadata/src/errors.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -307,15 +307,10 @@ pub struct FailCreateFileEncoder {
307307
pub err: Error,
308308
}
309309

310-
#[derive(Diagnostic)]
311-
#[diag(metadata_fail_seek_file)]
312-
pub struct FailSeekFile {
313-
pub err: Error,
314-
}
315-
316310
#[derive(Diagnostic)]
317311
#[diag(metadata_fail_write_file)]
318-
pub struct FailWriteFile {
312+
pub struct FailWriteFile<'a> {
313+
pub path: &'a Path,
319314
pub err: Error,
320315
}
321316

compiler/rustc_metadata/src/rmeta/encoder.rs

+26-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::errors::{FailCreateFileEncoder, FailSeekFile, FailWriteFile};
1+
use crate::errors::{FailCreateFileEncoder, FailWriteFile};
22
use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
33
use crate::rmeta::table::TableBuilder;
44
use crate::rmeta::*;
@@ -41,6 +41,7 @@ use rustc_span::symbol::{sym, Symbol};
4141
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SpanData, SyntaxContext};
4242
use std::borrow::Borrow;
4343
use std::collections::hash_map::Entry;
44+
use std::fs::File;
4445
use std::hash::Hash;
4546
use std::io::{Read, Seek, Write};
4647
use std::num::NonZeroUsize;
@@ -2251,22 +2252,17 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
22512252
// culminating in the `CrateRoot` which points to all of it.
22522253
let root = ecx.encode_crate_root();
22532254

2254-
ecx.opaque.flush();
2255-
2256-
let mut file = ecx.opaque.file();
2257-
// We will return to this position after writing the root position.
2258-
let pos_before_seek = file.stream_position().unwrap();
2259-
2260-
// Encode the root position.
2261-
let header = METADATA_HEADER.len();
2262-
file.seek(std::io::SeekFrom::Start(header as u64))
2263-
.unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err }));
2264-
let pos = root.position.get();
2265-
file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8])
2266-
.unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err }));
2255+
// Make sure we report any errors from writing to the file.
2256+
// If we forget this, compilation can succeed with an incomplete rmeta file,
2257+
// causing an ICE when the rmeta file is read by another compilation.
2258+
if let Err((path, err)) = ecx.opaque.finish() {
2259+
tcx.sess.emit_err(FailWriteFile { path: &path, err });
2260+
}
22672261

2268-
// Return to the position where we are before writing the root position.
2269-
file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap();
2262+
let file = ecx.opaque.file();
2263+
if let Err(err) = encode_root_position(file, root.position.get()) {
2264+
tcx.sess.emit_err(FailWriteFile { path: ecx.opaque.path(), err });
2265+
}
22702266

22712267
// Record metadata size for self-profiling
22722268
tcx.prof.artifact_size(
@@ -2276,6 +2272,20 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
22762272
);
22772273
}
22782274

2275+
fn encode_root_position(mut file: &File, pos: usize) -> Result<(), std::io::Error> {
2276+
// We will return to this position after writing the root position.
2277+
let pos_before_seek = file.stream_position().unwrap();
2278+
2279+
// Encode the root position.
2280+
let header = METADATA_HEADER.len();
2281+
file.seek(std::io::SeekFrom::Start(header as u64))?;
2282+
file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8])?;
2283+
2284+
// Return to the position where we are before writing the root position.
2285+
file.seek(std::io::SeekFrom::Start(pos_before_seek))?;
2286+
Ok(())
2287+
}
2288+
22792289
pub fn provide(providers: &mut Providers) {
22802290
*providers = Providers {
22812291
doc_link_resolutions: |tcx, def_id| {

compiler/rustc_middle/src/query/on_disk_cache.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use rustc_span::source_map::{SourceMap, StableSourceFileId};
2525
use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span};
2626
use rustc_span::{CachingSourceMapView, Symbol};
2727
use std::collections::hash_map::Entry;
28-
use std::io;
2928
use std::mem;
3029

3130
const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
@@ -867,7 +866,7 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> {
867866
}
868867

869868
#[inline]
870-
fn finish(self) -> Result<usize, io::Error> {
869+
fn finish(mut self) -> FileEncodeResult {
871870
self.encoder.finish()
872871
}
873872
}

compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,10 @@ impl<'tcx> GlobalCtxt<'tcx> {
606606
let icx = tls::ImplicitCtxt::new(self);
607607
tls::enter_context(&icx, || f(icx.tcx))
608608
}
609+
610+
pub fn finish(&self) -> FileEncodeResult {
611+
self.dep_graph.finish_encoding(&self.sess.prof)
612+
}
609613
}
610614

611615
impl<'tcx> TyCtxt<'tcx> {

compiler/rustc_query_system/src/dep_graph/graph.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ impl<D: Deps> DepGraph<D> {
982982
}
983983
}
984984

985-
pub fn encode(&self, profiler: &SelfProfilerRef) -> FileEncodeResult {
985+
pub fn finish_encoding(&self, profiler: &SelfProfilerRef) -> FileEncodeResult {
986986
if let Some(data) = &self.data {
987987
data.current.encoder.steal().finish(profiler)
988988
} else {

compiler/rustc_serialize/src/opaque.rs

+36-7
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use std::io::{self, Write};
55
use std::marker::PhantomData;
66
use std::ops::Range;
77
use std::path::Path;
8+
use std::path::PathBuf;
89

910
// -----------------------------------------------------------------------------
1011
// Encoder
1112
// -----------------------------------------------------------------------------
1213

13-
pub type FileEncodeResult = Result<usize, io::Error>;
14+
pub type FileEncodeResult = Result<usize, (PathBuf, io::Error)>;
1415

1516
/// The size of the buffer in `FileEncoder`.
1617
const BUF_SIZE: usize = 8192;
@@ -34,21 +35,28 @@ pub struct FileEncoder {
3435
// This is used to implement delayed error handling, as described in the
3536
// comment on `trait Encoder`.
3637
res: Result<(), io::Error>,
38+
path: PathBuf,
39+
#[cfg(debug_assertions)]
40+
finished: bool,
3741
}
3842

3943
impl FileEncoder {
4044
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
4145
// File::create opens the file for writing only. When -Zmeta-stats is enabled, the metadata
4246
// encoder rewinds the file to inspect what was written. So we need to always open the file
4347
// for reading and writing.
44-
let file = File::options().read(true).write(true).create(true).truncate(true).open(path)?;
48+
let file =
49+
File::options().read(true).write(true).create(true).truncate(true).open(&path)?;
4550

4651
Ok(FileEncoder {
4752
buf: vec![0u8; BUF_SIZE].into_boxed_slice().try_into().unwrap(),
53+
path: path.as_ref().into(),
4854
buffered: 0,
4955
flushed: 0,
5056
file,
5157
res: Ok(()),
58+
#[cfg(debug_assertions)]
59+
finished: false,
5260
})
5361
}
5462

@@ -63,6 +71,10 @@ impl FileEncoder {
6371
#[cold]
6472
#[inline(never)]
6573
pub fn flush(&mut self) {
74+
#[cfg(debug_assertions)]
75+
{
76+
self.finished = false;
77+
}
6678
if self.res.is_ok() {
6779
self.res = self.file.write_all(&self.buf[..self.buffered]);
6880
}
@@ -74,6 +86,10 @@ impl FileEncoder {
7486
&self.file
7587
}
7688

89+
pub fn path(&self) -> &Path {
90+
&self.path
91+
}
92+
7793
#[inline]
7894
fn buffer_empty(&mut self) -> &mut [u8] {
7995
// SAFETY: self.buffered is inbounds as an invariant of the type
@@ -97,6 +113,10 @@ impl FileEncoder {
97113

98114
#[inline]
99115
fn write_all(&mut self, buf: &[u8]) {
116+
#[cfg(debug_assertions)]
117+
{
118+
self.finished = false;
119+
}
100120
if let Some(dest) = self.buffer_empty().get_mut(..buf.len()) {
101121
dest.copy_from_slice(buf);
102122
self.buffered += buf.len();
@@ -121,6 +141,10 @@ impl FileEncoder {
121141
/// with one instruction, so while this does in some sense do wasted work, we come out ahead.
122142
#[inline]
123143
pub fn write_with<const N: usize>(&mut self, visitor: impl FnOnce(&mut [u8; N]) -> usize) {
144+
#[cfg(debug_assertions)]
145+
{
146+
self.finished = false;
147+
}
124148
let flush_threshold = const { BUF_SIZE.checked_sub(N).unwrap() };
125149
if std::intrinsics::unlikely(self.buffered > flush_threshold) {
126150
self.flush();
@@ -152,20 +176,25 @@ impl FileEncoder {
152176
})
153177
}
154178

155-
pub fn finish(mut self) -> Result<usize, io::Error> {
179+
pub fn finish(&mut self) -> FileEncodeResult {
156180
self.flush();
181+
#[cfg(debug_assertions)]
182+
{
183+
self.finished = true;
184+
}
157185
match std::mem::replace(&mut self.res, Ok(())) {
158186
Ok(()) => Ok(self.position()),
159-
Err(e) => Err(e),
187+
Err(e) => Err((self.path.clone(), e)),
160188
}
161189
}
162190
}
163191

192+
#[cfg(debug_assertions)]
164193
impl Drop for FileEncoder {
165194
fn drop(&mut self) {
166-
// Likely to be a no-op, because `finish` should have been called and
167-
// it also flushes. But do it just in case.
168-
self.flush();
195+
if !std::thread::panicking() {
196+
assert!(self.finished);
197+
}
169198
}
170199
}
171200

src/librustdoc/scrape_examples.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ pub(crate) fn run(
325325
// Save output to provided path
326326
let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?;
327327
calls.encode(&mut encoder);
328-
encoder.finish().map_err(|e| e.to_string())?;
328+
encoder.finish().map_err(|(_path, e)| e.to_string())?;
329329

330330
Ok(())
331331
};

0 commit comments

Comments
 (0)