Skip to content

Commit 410a39f

Browse files
authored
Rollup merge of rust-lang#64374 - nnethercote:box-DiagnosticBuilder, r=zackmdavis
Box `DiagnosticBuilder`. It's a large type -- 176 bytes on 64-bit. And it's passed around and returned from a lot of functions, including within `PResult`. This commit boxes it, which reduces memory traffic. In particular, `PResult` shrinks to 16 bytes in the best case; this reduces instruction counts by up to 2% on various workloads. The commit touches a lot of lines but it's almost all trivial plumbing changes.
2 parents ea35453 + 2fcd870 commit 410a39f

File tree

4 files changed

+55
-37
lines changed

4 files changed

+55
-37
lines changed

src/librustc_errors/annotate_snippet_emitter_writer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl Emitter for AnnotateSnippetEmitterWriter {
3737
&mut primary_span,
3838
&mut children,
3939
&db.level,
40-
db.handler.flags.external_macro_backtrace);
40+
db.handler().flags.external_macro_backtrace);
4141

4242
self.emit_messages_default(&db.level,
4343
db.message(),

src/librustc_errors/diagnostic_builder.rs

+46-35
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,17 @@ use log::debug;
1818
/// extending `HandlerFlags`, accessed via `self.handler.flags`.
1919
#[must_use]
2020
#[derive(Clone)]
21-
pub struct DiagnosticBuilder<'a> {
22-
pub handler: &'a Handler,
21+
pub struct DiagnosticBuilder<'a>(Box<DiagnosticBuilderInner<'a>>);
22+
23+
/// This is a large type, and often used as a return value, especially within
24+
/// the frequently-used `PResult` type. In theory, return value optimization
25+
/// (RVO) should avoid unnecessary copying. In practice, it does not (at the
26+
/// time of writing). The split between `DiagnosticBuilder` and
27+
/// `DiagnosticBuilderInner` exists to avoid many `memcpy` calls.
28+
#[must_use]
29+
#[derive(Clone)]
30+
struct DiagnosticBuilderInner<'a> {
31+
handler: &'a Handler,
2332
diagnostic: Diagnostic,
2433
allow_suggestions: bool,
2534
}
@@ -52,7 +61,7 @@ macro_rules! forward {
5261
) => {
5362
$(#[$attrs])*
5463
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
55-
self.diagnostic.$n($($name),*);
64+
self.0.diagnostic.$n($($name),*);
5665
self
5766
}
5867
};
@@ -69,7 +78,7 @@ macro_rules! forward {
6978
) => {
7079
$(#[$attrs])*
7180
pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
72-
self.diagnostic.$n($($name),*);
81+
self.0.diagnostic.$n($($name),*);
7382
self
7483
}
7584
};
@@ -79,24 +88,28 @@ impl<'a> Deref for DiagnosticBuilder<'a> {
7988
type Target = Diagnostic;
8089

8190
fn deref(&self) -> &Diagnostic {
82-
&self.diagnostic
91+
&self.0.diagnostic
8392
}
8493
}
8594

8695
impl<'a> DerefMut for DiagnosticBuilder<'a> {
8796
fn deref_mut(&mut self) -> &mut Diagnostic {
88-
&mut self.diagnostic
97+
&mut self.0.diagnostic
8998
}
9099
}
91100

92101
impl<'a> DiagnosticBuilder<'a> {
102+
pub fn handler(&self) -> &'a Handler{
103+
self.0.handler
104+
}
105+
93106
/// Emit the diagnostic.
94107
pub fn emit(&mut self) {
95108
if self.cancelled() {
96109
return;
97110
}
98111

99-
self.handler.emit_db(&self);
112+
self.0.handler.emit_db(&self);
100113
self.cancel();
101114
}
102115

@@ -115,8 +128,8 @@ impl<'a> DiagnosticBuilder<'a> {
115128
/// Buffers the diagnostic for later emission, unless handler
116129
/// has disabled such buffering.
117130
pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
118-
if self.handler.flags.dont_buffer_diagnostics ||
119-
self.handler.flags.treat_err_as_bug.is_some()
131+
if self.0.handler.flags.dont_buffer_diagnostics ||
132+
self.0.handler.flags.treat_err_as_bug.is_some()
120133
{
121134
self.emit();
122135
return;
@@ -126,7 +139,7 @@ impl<'a> DiagnosticBuilder<'a> {
126139
// implements `Drop`.
127140
let diagnostic;
128141
unsafe {
129-
diagnostic = std::ptr::read(&self.diagnostic);
142+
diagnostic = std::ptr::read(&self.0.diagnostic);
130143
std::mem::forget(self);
131144
};
132145
// Logging here is useful to help track down where in logs an error was
@@ -144,7 +157,7 @@ impl<'a> DiagnosticBuilder<'a> {
144157
span: Option<S>,
145158
) -> &mut Self {
146159
let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new());
147-
self.diagnostic.sub(level, message, span, None);
160+
self.0.diagnostic.sub(level, message, span, None);
148161
self
149162
}
150163

@@ -160,7 +173,7 @@ impl<'a> DiagnosticBuilder<'a> {
160173
/// locally in whichever way makes the most sense.
161174
pub fn delay_as_bug(&mut self) {
162175
self.level = Level::Bug;
163-
self.handler.delay_as_bug(self.diagnostic.clone());
176+
self.0.handler.delay_as_bug(self.0.diagnostic.clone());
164177
self.cancel();
165178
}
166179

@@ -171,7 +184,7 @@ impl<'a> DiagnosticBuilder<'a> {
171184
/// then the snippet will just include that `Span`, which is
172185
/// called the primary span.
173186
pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
174-
self.diagnostic.span_label(span, label);
187+
self.0.diagnostic.span_label(span, label);
175188
self
176189
}
177190

@@ -208,10 +221,10 @@ impl<'a> DiagnosticBuilder<'a> {
208221
suggestion: Vec<(Span, String)>,
209222
applicability: Applicability,
210223
) -> &mut Self {
211-
if !self.allow_suggestions {
224+
if !self.0.allow_suggestions {
212225
return self
213226
}
214-
self.diagnostic.multipart_suggestion(
227+
self.0.diagnostic.multipart_suggestion(
215228
msg,
216229
suggestion,
217230
applicability,
@@ -225,29 +238,28 @@ impl<'a> DiagnosticBuilder<'a> {
225238
suggestion: Vec<(Span, String)>,
226239
applicability: Applicability,
227240
) -> &mut Self {
228-
if !self.allow_suggestions {
241+
if !self.0.allow_suggestions {
229242
return self
230243
}
231-
self.diagnostic.tool_only_multipart_suggestion(
244+
self.0.diagnostic.tool_only_multipart_suggestion(
232245
msg,
233246
suggestion,
234247
applicability,
235248
);
236249
self
237250
}
238251

239-
240252
pub fn span_suggestion(
241253
&mut self,
242254
sp: Span,
243255
msg: &str,
244256
suggestion: String,
245257
applicability: Applicability,
246258
) -> &mut Self {
247-
if !self.allow_suggestions {
259+
if !self.0.allow_suggestions {
248260
return self
249261
}
250-
self.diagnostic.span_suggestion(
262+
self.0.diagnostic.span_suggestion(
251263
sp,
252264
msg,
253265
suggestion,
@@ -263,10 +275,10 @@ impl<'a> DiagnosticBuilder<'a> {
263275
suggestions: impl Iterator<Item = String>,
264276
applicability: Applicability,
265277
) -> &mut Self {
266-
if !self.allow_suggestions {
278+
if !self.0.allow_suggestions {
267279
return self
268280
}
269-
self.diagnostic.span_suggestions(
281+
self.0.diagnostic.span_suggestions(
270282
sp,
271283
msg,
272284
suggestions,
@@ -282,10 +294,10 @@ impl<'a> DiagnosticBuilder<'a> {
282294
suggestion: String,
283295
applicability: Applicability,
284296
) -> &mut Self {
285-
if !self.allow_suggestions {
297+
if !self.0.allow_suggestions {
286298
return self
287299
}
288-
self.diagnostic.span_suggestion_short(
300+
self.0.diagnostic.span_suggestion_short(
289301
sp,
290302
msg,
291303
suggestion,
@@ -301,10 +313,10 @@ impl<'a> DiagnosticBuilder<'a> {
301313
suggestion: String,
302314
applicability: Applicability,
303315
) -> &mut Self {
304-
if !self.allow_suggestions {
316+
if !self.0.allow_suggestions {
305317
return self
306318
}
307-
self.diagnostic.span_suggestion_hidden(
319+
self.0.diagnostic.span_suggestion_hidden(
308320
sp,
309321
msg,
310322
suggestion,
@@ -320,10 +332,10 @@ impl<'a> DiagnosticBuilder<'a> {
320332
suggestion: String,
321333
applicability: Applicability,
322334
) -> &mut Self {
323-
if !self.allow_suggestions {
335+
if !self.0.allow_suggestions {
324336
return self
325337
}
326-
self.diagnostic.tool_only_span_suggestion(
338+
self.0.diagnostic.tool_only_span_suggestion(
327339
sp,
328340
msg,
329341
suggestion,
@@ -336,7 +348,7 @@ impl<'a> DiagnosticBuilder<'a> {
336348
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
337349

338350
pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
339-
self.allow_suggestions = allow;
351+
self.0.allow_suggestions = allow;
340352
self
341353
}
342354

@@ -359,19 +371,18 @@ impl<'a> DiagnosticBuilder<'a> {
359371

360372
/// Creates a new `DiagnosticBuilder` with an already constructed
361373
/// diagnostic.
362-
pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
363-
-> DiagnosticBuilder<'a> {
364-
DiagnosticBuilder {
374+
pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
375+
DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
365376
handler,
366377
diagnostic,
367378
allow_suggestions: true,
368-
}
379+
}))
369380
}
370381
}
371382

372383
impl<'a> Debug for DiagnosticBuilder<'a> {
373384
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374-
self.diagnostic.fmt(f)
385+
self.0.diagnostic.fmt(f)
375386
}
376387
}
377388

@@ -381,7 +392,7 @@ impl<'a> Drop for DiagnosticBuilder<'a> {
381392
fn drop(&mut self) {
382393
if !panicking() && !self.cancelled() {
383394
let mut db = DiagnosticBuilder::new(
384-
self.handler,
395+
self.0.handler,
385396
Level::Bug,
386397
"the following error was constructed but not emitted",
387398
);

src/librustc_errors/emitter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ impl Emitter for EmitterWriter {
385385
&mut primary_span,
386386
&mut children,
387387
&db.level,
388-
db.handler.flags.external_macro_backtrace);
388+
db.handler().flags.external_macro_backtrace);
389389

390390
self.emit_messages_default(&db.level,
391391
&db.styled_message(),

src/libsyntax/parse/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use crate::symbol::Symbol;
1313

1414
use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
1515
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
16+
#[cfg(target_arch = "x86_64")]
17+
use rustc_data_structures::static_assert_size;
1618
use rustc_data_structures::sync::{Lrc, Lock, Once};
1719
use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
1820
use syntax_pos::edition::Edition;
@@ -38,6 +40,11 @@ crate mod unescape_error_reporting;
3840

3941
pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
4042

43+
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
44+
// (See also the comment on `DiagnosticBuilderInner`.)
45+
#[cfg(target_arch = "x86_64")]
46+
static_assert_size!(PResult<'_, bool>, 16);
47+
4148
/// Collected spans during parsing for places where a certain feature was
4249
/// used and should be feature gated accordingly in `check_crate`.
4350
#[derive(Default)]

0 commit comments

Comments
 (0)