Skip to content

Commit 6da912e

Browse files
committed
Merge branch 'explain' of https://github.com/estebank/rust into rollup
2 parents 9594215 + 2b73733 commit 6da912e

File tree

12 files changed

+231
-44
lines changed

12 files changed

+231
-44
lines changed

src/librustc/session/config.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
11671167
"treat all errors that occur as bugs"),
11681168
external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
11691169
"show macro backtraces even for non-local macros"),
1170+
teach: bool = (false, parse_bool, [TRACKED],
1171+
"show extended diagnostic help"),
11701172
continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
11711173
"attempt to recover from parse errors (experimental)"),
11721174
incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
@@ -1664,8 +1666,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
16641666
let mut debugging_opts = build_debugging_options(matches, error_format);
16651667

16661668
if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
1667-
early_error(ErrorOutputType::Json(false),
1668-
"--error-format=pretty-json is unstable");
1669+
early_error(ErrorOutputType::Json(false), "--error-format=pretty-json is unstable");
16691670
}
16701671

16711672
let mut output_types = BTreeMap::new();

src/librustc/session/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,10 @@ impl Session {
860860
// scientific.
861861
16
862862
}
863+
864+
pub fn teach(&self, code: &DiagnosticId) -> bool {
865+
self.opts.debugging_opts.teach && !self.parse_sess.span_diagnostic.code_emitted(code)
866+
}
863867
}
864868

865869
pub fn build_session(sopts: config::Options,

src/librustc_errors/diagnostic.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub struct Diagnostic {
2727
pub suggestions: Vec<CodeSuggestion>,
2828
}
2929

30-
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
30+
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
3131
pub enum DiagnosticId {
3232
Error(String),
3333
Lint(String),
@@ -281,6 +281,10 @@ impl Diagnostic {
281281
self
282282
}
283283

284+
pub fn get_code(&self) -> Option<DiagnosticId> {
285+
self.code.clone()
286+
}
287+
284288
pub fn message(&self) -> String {
285289
self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
286290
}

src/librustc_errors/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@ pub struct Handler {
259259
delayed_span_bug: RefCell<Option<Diagnostic>>,
260260
tracked_diagnostics: RefCell<Option<Vec<Diagnostic>>>,
261261

262+
// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
263+
// emitting the same diagnostic with extended help (`--teach`) twice, which
264+
// would be uneccessary repetition.
265+
tracked_diagnostic_codes: RefCell<FxHashSet<DiagnosticId>>,
266+
262267
// This set contains a hash of every diagnostic that has been emitted by
263268
// this handler. These hashes is used to avoid emitting the same error
264269
// twice.
@@ -317,6 +322,7 @@ impl Handler {
317322
continue_after_error: Cell::new(true),
318323
delayed_span_bug: RefCell::new(None),
319324
tracked_diagnostics: RefCell::new(None),
325+
tracked_diagnostic_codes: RefCell::new(FxHashSet()),
320326
emitted_diagnostics: RefCell::new(FxHashSet()),
321327
}
322328
}
@@ -589,13 +595,25 @@ impl Handler {
589595
(ret, diagnostics)
590596
}
591597

598+
/// `true` if a diagnostic with this code has already been emitted in this handler.
599+
///
600+
/// Used to suppress emitting the same error multiple times with extended explanation when
601+
/// calling `-Zteach`.
602+
pub fn code_emitted(&self, code: &DiagnosticId) -> bool {
603+
self.tracked_diagnostic_codes.borrow().contains(code)
604+
}
605+
592606
fn emit_db(&self, db: &DiagnosticBuilder) {
593607
let diagnostic = &**db;
594608

595609
if let Some(ref mut list) = *self.tracked_diagnostics.borrow_mut() {
596610
list.push(diagnostic.clone());
597611
}
598612

613+
if let Some(ref code) = diagnostic.code {
614+
self.tracked_diagnostic_codes.borrow_mut().insert(code.clone());
615+
}
616+
599617
let diagnostic_hash = {
600618
use std::hash::Hash;
601619
let mut hasher = StableHasher::new();

src/librustc_typeck/check/cast.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
281281
.emit();
282282
}
283283
CastError::SizedUnsizedCast => {
284-
type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0607,
285-
"cannot cast thin pointer `{}` to fat pointer `{}`",
286-
self.expr_ty,
287-
fcx.ty_to_string(self.cast_ty)).emit();
284+
use structured_errors::{SizedUnsizedCastError, StructuredDiagnostic};
285+
SizedUnsizedCastError::new(&fcx.tcx.sess,
286+
self.span,
287+
self.expr_ty,
288+
fcx.ty_to_string(self.cast_ty))
289+
.diagnostic().emit();
288290
}
289291
CastError::UnknownCastPtrKind |
290292
CastError::UnknownExprPtrKind => {

src/librustc_typeck/check/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ use rustc::ty::maps::Providers;
103103
use rustc::ty::util::{Representability, IntTypeExt};
104104
use rustc::ty::layout::LayoutOf;
105105
use errors::{DiagnosticBuilder, DiagnosticId};
106+
106107
use require_c_abi_if_variadic;
107108
use session::{CompileIncomplete, config, Session};
108109
use TypeAndSubsts;
@@ -2599,9 +2600,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
25992600
// arguments which we skipped above.
26002601
if variadic {
26012602
fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
2602-
type_error_struct!(s, span, t, E0617,
2603-
"can't pass `{}` to variadic function, cast to `{}`",
2604-
t, cast_ty).emit();
2603+
use structured_errors::{VariadicError, StructuredDiagnostic};
2604+
VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
26052605
}
26062606

26072607
for arg in args.iter().skip(expected_arg_count) {

src/librustc_typeck/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,17 @@ use std::iter;
123123
// registered before they are used.
124124
mod diagnostics;
125125

126+
mod astconv;
126127
mod check;
127128
mod check_unused;
128-
mod astconv;
129+
mod coherence;
129130
mod collect;
130131
mod constrained_type_params;
132+
mod structured_errors;
131133
mod impl_wf_check;
132-
mod coherence;
134+
mod namespace;
133135
mod outlives;
134136
mod variance;
135-
mod namespace;
136137

137138
pub struct TypeAndSubsts<'tcx> {
138139
substs: &'tcx Substs<'tcx>,
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright 2018 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+
use rustc::session::Session;
12+
use syntax_pos::Span;
13+
use errors::{DiagnosticId, DiagnosticBuilder};
14+
use rustc::ty::{Ty, TypeFoldable};
15+
16+
pub trait StructuredDiagnostic<'tcx> {
17+
fn session(&self) -> &Session;
18+
19+
fn code(&self) -> DiagnosticId;
20+
21+
fn common(&self) -> DiagnosticBuilder<'tcx>;
22+
23+
fn diagnostic(&self) -> DiagnosticBuilder<'tcx> {
24+
let err = self.common();
25+
if self.session().teach(&self.code()) {
26+
self.extended(err)
27+
} else {
28+
self.regular(err)
29+
}
30+
}
31+
32+
fn regular(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
33+
err
34+
}
35+
36+
fn extended(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
37+
err
38+
}
39+
}
40+
41+
pub struct VariadicError<'tcx> {
42+
sess: &'tcx Session,
43+
span: Span,
44+
t: Ty<'tcx>,
45+
cast_ty: &'tcx str,
46+
}
47+
48+
impl<'tcx> VariadicError<'tcx> {
49+
pub fn new(sess: &'tcx Session,
50+
span: Span,
51+
t: Ty<'tcx>,
52+
cast_ty: &'tcx str) -> VariadicError<'tcx> {
53+
VariadicError { sess, span, t, cast_ty }
54+
}
55+
}
56+
57+
impl<'tcx> StructuredDiagnostic<'tcx> for VariadicError<'tcx> {
58+
fn session(&self) -> &Session { self.sess }
59+
60+
fn code(&self) -> DiagnosticId {
61+
__diagnostic_used!(E0617);
62+
DiagnosticId::Error("E0617".to_owned())
63+
}
64+
65+
fn common(&self) -> DiagnosticBuilder<'tcx> {
66+
let mut err = if self.t.references_error() {
67+
self.sess.diagnostic().struct_dummy()
68+
} else {
69+
self.sess.struct_span_fatal_with_code(
70+
self.span,
71+
&format!("can't pass `{}` to variadic function", self.t),
72+
self.code(),
73+
)
74+
};
75+
if let Ok(snippet) = self.sess.codemap().span_to_snippet(self.span) {
76+
err.span_suggestion(self.span,
77+
&format!("cast the value to `{}`", self.cast_ty),
78+
format!("{} as {}", snippet, self.cast_ty));
79+
} else {
80+
err.help(&format!("cast the value to `{}`", self.cast_ty));
81+
}
82+
err
83+
}
84+
85+
fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
86+
err.note(&format!("certain types, like `{}`, must be cast before passing them to a \
87+
variadic function, because of arcane ABI rules dictated by the C \
88+
standard",
89+
self.t));
90+
err
91+
}
92+
}
93+
94+
pub struct SizedUnsizedCastError<'tcx> {
95+
sess: &'tcx Session,
96+
span: Span,
97+
expr_ty: Ty<'tcx>,
98+
cast_ty: String,
99+
}
100+
101+
impl<'tcx> SizedUnsizedCastError<'tcx> {
102+
pub fn new(sess: &'tcx Session,
103+
span: Span,
104+
expr_ty: Ty<'tcx>,
105+
cast_ty: String) -> SizedUnsizedCastError<'tcx> {
106+
SizedUnsizedCastError { sess, span, expr_ty, cast_ty }
107+
}
108+
}
109+
110+
impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCastError<'tcx> {
111+
fn session(&self) -> &Session { self.sess }
112+
113+
fn code(&self) -> DiagnosticId {
114+
__diagnostic_used!(E0607);
115+
DiagnosticId::Error("E0607".to_owned())
116+
}
117+
118+
fn common(&self) -> DiagnosticBuilder<'tcx> {
119+
if self.expr_ty.references_error() {
120+
self.sess.diagnostic().struct_dummy()
121+
} else {
122+
self.sess.struct_span_fatal_with_code(
123+
self.span,
124+
&format!("cannot cast thin pointer `{}` to fat pointer `{}`",
125+
self.expr_ty,
126+
self.cast_ty),
127+
self.code(),
128+
)
129+
}
130+
}
131+
132+
fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
133+
err.help(
134+
"Thin pointers are \"simple\" pointers: they are purely a reference to a
135+
memory address.
136+
137+
Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
138+
called DST). DST don't have a statically known size, therefore they can
139+
only exist behind some kind of pointers that contain additional
140+
information. Slices and trait objects are DSTs. In the case of slices,
141+
the additional information the fat pointer holds is their size.
142+
143+
To fix this error, don't try to cast directly between thin and fat
144+
pointers.
145+
146+
For more information about casts, take a look at The Book:
147+
https://doc.rust-lang.org/book/first-edition/casting-between-types.html");
148+
err
149+
}
150+
}

src/test/compile-fail/E0617.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,22 @@ extern {
1717
fn main() {
1818
unsafe {
1919
printf(::std::ptr::null(), 0f32);
20-
//~^ ERROR can't pass `f32` to variadic function, cast to `c_double` [E0617]
20+
//~^ ERROR can't pass `f32` to variadic function
21+
//~| HELP cast the value to `c_double`
2122
printf(::std::ptr::null(), 0i8);
22-
//~^ ERROR can't pass `i8` to variadic function, cast to `c_int` [E0617]
23+
//~^ ERROR can't pass `i8` to variadic function
24+
//~| HELP cast the value to `c_int`
2325
printf(::std::ptr::null(), 0i16);
24-
//~^ ERROR can't pass `i16` to variadic function, cast to `c_int` [E0617]
26+
//~^ ERROR can't pass `i16` to variadic function
27+
//~| HELP cast the value to `c_int`
2528
printf(::std::ptr::null(), 0u8);
26-
//~^ ERROR can't pass `u8` to variadic function, cast to `c_uint` [E0617]
29+
//~^ ERROR can't pass `u8` to variadic function
30+
//~| HELP cast the value to `c_uint`
2731
printf(::std::ptr::null(), 0u16);
28-
//~^ ERROR can't pass `u16` to variadic function, cast to `c_uint` [E0617]
32+
//~^ ERROR can't pass `u16` to variadic function
33+
//~| HELP cast the value to `c_uint`
2934
printf(::std::ptr::null(), printf);
30-
//~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function, cast to `unsafe extern "C" fn(*const i8, ...)` [E0617]
35+
//~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function
36+
//~| HELP cast the value to `unsafe extern "C" fn(*const i8, ...)`
3137
}
3238
}

src/test/compile-fail/issue-32201.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ fn bar(_: *const u8) {}
1717
fn main() {
1818
unsafe {
1919
foo(0, bar);
20-
//~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function, cast to `fn(*const u8)`
20+
//~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function
21+
//~| HELP cast the value to `fn(*const u8)`
2122
}
2223
}

src/test/ui/variadic-ffi-3.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ fn main() {
3131
//~| expected type `extern "C" fn(isize, u8, ...)`
3232
//~| found type `extern "C" fn(isize, u8) {bar}`
3333

34-
foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function, cast to `c_double`
35-
foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function, cast to `c_int`
36-
foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function, cast to `c_int`
37-
foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function, cast to `c_uint`
38-
foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function, cast to `c_int`
39-
foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function, cast to `c_uint`
34+
foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function
35+
foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function
36+
foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function
37+
foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function
38+
foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function
39+
foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function
4040
}
4141
}

0 commit comments

Comments
 (0)