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