Skip to content

Commit e87e0bc

Browse files
committed
Add -Zteach documentation
Add extra inline documentation to E0019, E0016, E0013, E0396, E0017, E0018, E0010, E0022, E0030, E0029, E0033, E0026 and E0027.
1 parent 29c8276 commit e87e0bc

File tree

4 files changed

+229
-55
lines changed

4 files changed

+229
-55
lines changed

src/librustc/middle/entry.rs

+4
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ fn configure_main(this: &mut EntryContext) {
175175
err.emit();
176176
this.session.abort_if_errors();
177177
} else {
178+
if this.session.teach(&err.get_code().unwrap()) {
179+
err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
180+
to get started: https://doc.rust-lang.org/book/");
181+
}
178182
err.emit();
179183
}
180184
}

src/librustc_mir/transform/qualify_consts.rs

+138-30
Original file line numberDiff line numberDiff line change
@@ -170,18 +170,40 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
170170
fn not_const(&mut self) {
171171
self.add(Qualif::NOT_CONST);
172172
if self.mode != Mode::Fn {
173-
span_err!(self.tcx.sess, self.span, E0019,
174-
"{} contains unimplemented expression type", self.mode);
173+
let mut err = struct_span_err!(
174+
self.tcx.sess,
175+
self.span,
176+
E0019,
177+
"{} contains unimplemented expression type",
178+
self.mode
179+
);
180+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
181+
err.note("A function call isn't allowed in the const's initialization expression \
182+
because the expression's value must be known at compile-time.");
183+
err.note("Remember: you can't use a function call inside a const's initialization \
184+
expression! However, you can use it anywhere else.");
185+
}
186+
err.emit();
175187
}
176188
}
177189

178190
/// Error about extra statements in a constant.
179191
fn statement_like(&mut self) {
180192
self.add(Qualif::NOT_CONST);
181193
if self.mode != Mode::Fn {
182-
span_err!(self.tcx.sess, self.span, E0016,
183-
"blocks in {}s are limited to items and tail expressions",
184-
self.mode);
194+
let mut err = struct_span_err!(
195+
self.tcx.sess,
196+
self.span,
197+
E0016,
198+
"blocks in {}s are limited to items and tail expressions",
199+
self.mode
200+
);
201+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
202+
err.note("Blocks in constants may only contain items (such as constant, function \
203+
definition, etc...) and a tail expression.");
204+
err.help("To avoid it, you have to replace the non-item object.");
205+
}
206+
err.emit();
185207
}
186208
}
187209

@@ -474,9 +496,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
474496
}
475497

476498
if self.mode == Mode::Const || self.mode == Mode::ConstFn {
477-
span_err!(self.tcx.sess, self.span, E0013,
478-
"{}s cannot refer to statics, use \
479-
a constant instead", self.mode);
499+
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
500+
"{}s cannot refer to statics, use \
501+
a constant instead", self.mode);
502+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
503+
err.note(
504+
"Static and const variables can refer to other const variables. But a \
505+
const variable cannot refer to a static variable."
506+
);
507+
err.help(
508+
"To fix this, the value can be extracted as a const and then used."
509+
);
510+
}
511+
err.emit()
480512
}
481513
}
482514
Place::Projection(ref proj) => {
@@ -497,13 +529,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
497529
if let ty::TyRawPtr(_) = base_ty.sty {
498530
this.add(Qualif::NOT_CONST);
499531
if this.mode != Mode::Fn {
500-
struct_span_err!(this.tcx.sess,
501-
this.span, E0396,
532+
let mut err = struct_span_err!(
533+
this.tcx.sess,
534+
this.span,
535+
E0396,
502536
"raw pointers cannot be dereferenced in {}s",
503-
this.mode)
504-
.span_label(this.span,
505-
"dereference of raw pointer in constant")
506-
.emit();
537+
this.mode
538+
);
539+
err.span_label(this.span,
540+
"dereference of raw pointer in constant");
541+
if this.tcx.sess.teach(&err.get_code().unwrap()) {
542+
err.note(
543+
"The value behind a raw pointer can't be determined \
544+
at compile-time (or even link-time), which means it \
545+
can't be used in a constant expression."
546+
);
547+
err.help("A possible fix is to dereference your pointer \
548+
at some point in run-time.");
549+
}
550+
err.emit();
507551
}
508552
}
509553
}
@@ -622,12 +666,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
622666
if !allow {
623667
self.add(Qualif::NOT_CONST);
624668
if self.mode != Mode::Fn {
625-
struct_span_err!(self.tcx.sess, self.span, E0017,
626-
"references in {}s may only refer \
627-
to immutable values", self.mode)
628-
.span_label(self.span, format!("{}s require immutable values",
629-
self.mode))
630-
.emit();
669+
let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
670+
"references in {}s may only refer \
671+
to immutable values", self.mode);
672+
err.span_label(self.span, format!("{}s require immutable values",
673+
self.mode));
674+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
675+
err.note("References in statics and constants may only refer to \
676+
immutable values.\n\n\
677+
Statics are shared everywhere, and if they refer to \
678+
mutable data one might violate memory safety since \
679+
holding multiple mutable references to shared data is \
680+
not allowed.\n\n\
681+
If you really want global mutable state, try using \
682+
static mut or a global UnsafeCell.");
683+
}
684+
err.emit();
631685
}
632686
}
633687
} else {
@@ -668,9 +722,42 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
668722
(CastTy::FnPtr, CastTy::Int(_)) => {
669723
self.add(Qualif::NOT_CONST);
670724
if self.mode != Mode::Fn {
671-
span_err!(self.tcx.sess, self.span, E0018,
672-
"raw pointers cannot be cast to integers in {}s",
673-
self.mode);
725+
let mut err = struct_span_err!(
726+
self.tcx.sess,
727+
self.span,
728+
E0018,
729+
"raw pointers cannot be cast to integers in {}s",
730+
self.mode
731+
);
732+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
733+
err.note("\
734+
The value of static and constant integers must be known at compile time. You can't cast a pointer \
735+
to an integer because the address of a pointer can vary.
736+
737+
For example, if you write:
738+
739+
```
740+
static MY_STATIC: u32 = 42;
741+
static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
742+
static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
743+
```
744+
745+
Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However, the address can change \
746+
when the program is linked, as well as change between different executions due to ASLR, and many \
747+
linkers would not be able to calculate the value of `WHAT`.
748+
749+
On the other hand, static and constant pointers can point either to a known numeric address or to \
750+
the address of a symbol.
751+
752+
```
753+
static MY_STATIC: u32 = 42;
754+
static MY_STATIC_ADDR: &'static u32 = &MY_STATIC;
755+
const CONST_ADDR: *const u8 = 0x5f3759df as *const u8;
756+
```
757+
758+
This does not pose a problem by itself because they can't be accessed directly.");
759+
}
760+
err.emit();
674761
}
675762
}
676763
_ => {}
@@ -701,10 +788,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
701788
Rvalue::NullaryOp(NullOp::Box, _) => {
702789
self.add(Qualif::NOT_CONST);
703790
if self.mode != Mode::Fn {
704-
struct_span_err!(self.tcx.sess, self.span, E0010,
705-
"allocations are not allowed in {}s", self.mode)
706-
.span_label(self.span, format!("allocation not allowed in {}s", self.mode))
707-
.emit();
791+
let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
792+
"allocations are not allowed in {}s", self.mode);
793+
err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
794+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
795+
err.note(
796+
"The value of statics and constants must be known at compile time, \
797+
and they live for the entire lifetime of a program. Creating a boxed \
798+
value allocates memory on the heap at runtime, and therefore cannot \
799+
be done at compile time."
800+
);
801+
}
802+
err.emit();
708803
}
709804
}
710805

@@ -930,9 +1025,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
9301025
// Avoid a generic error for other uses of arguments.
9311026
if self.qualif.intersects(Qualif::FN_ARGUMENT) {
9321027
let decl = &self.mir.local_decls[index];
933-
span_err!(self.tcx.sess, decl.source_info.span, E0022,
934-
"arguments of constant functions can only \
935-
be immutable by-value bindings");
1028+
let mut err = struct_span_err!(
1029+
self.tcx.sess,
1030+
decl.source_info.span,
1031+
E0022,
1032+
"arguments of constant functions can only be immutable by-value bindings"
1033+
);
1034+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
1035+
err.note("Constant functions are not allowed to mutate anything. Thus, \
1036+
binding to an argument with a mutable pattern is not allowed.");
1037+
err.note("Remove any mutable bindings from the argument list to fix this \
1038+
error. In case you need to mutate the argument, try lazily \
1039+
initializing a global variable instead of using a const fn, or \
1040+
refactoring the code to a functional style to avoid mutation if \
1041+
possible.");
1042+
}
1043+
err.emit();
9361044
return;
9371045
}
9381046
}

src/librustc_passes/consts.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,20 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
237237
Ok(Ordering::Less) |
238238
Ok(Ordering::Equal) => {}
239239
Ok(Ordering::Greater) => {
240-
struct_span_err!(self.tcx.sess, start.span, E0030,
241-
"lower range bound must be less than or equal to upper")
242-
.span_label(start.span, "lower bound larger than upper bound")
243-
.emit();
240+
let mut err = struct_span_err!(
241+
self.tcx.sess,
242+
start.span,
243+
E0030,
244+
"lower range bound must be less than or equal to upper"
245+
);
246+
err.span_label(start.span, "lower bound larger than upper bound");
247+
if self.tcx.sess.teach(&err.get_code().unwrap()) {
248+
err.note("When matching against a range, the compiler verifies that \
249+
the range is non-empty. Range patterns include both \
250+
end-points, so this is equivalent to requiring the start of \
251+
the range to be less than or equal to the end of the range.");
252+
}
253+
err.emit();
244254
}
245255
Err(ErrorReported) => {}
246256
}

0 commit comments

Comments
 (0)