mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-23 21:23:20 +00:00
Add -Zteach
documentation
Add extra inline documentation to E0019, E0016, E0013, E0396, E0017, E0018, E0010, E0022, E0030, E0029, E0033, E0026 and E0027.
This commit is contained in:
parent
29c8276cee
commit
e87e0bcc0e
@ -175,6 +175,10 @@ fn configure_main(this: &mut EntryContext) {
|
||||
err.emit();
|
||||
this.session.abort_if_errors();
|
||||
} else {
|
||||
if this.session.teach(&err.get_code().unwrap()) {
|
||||
err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
|
||||
to get started: https://doc.rust-lang.org/book/");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +170,20 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
||||
fn not_const(&mut self) {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
if self.mode != Mode::Fn {
|
||||
span_err!(self.tcx.sess, self.span, E0019,
|
||||
"{} contains unimplemented expression type", self.mode);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.span,
|
||||
E0019,
|
||||
"{} contains unimplemented expression type",
|
||||
self.mode
|
||||
);
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("A function call isn't allowed in the const's initialization expression \
|
||||
because the expression's value must be known at compile-time.");
|
||||
err.note("Remember: you can't use a function call inside a const's initialization \
|
||||
expression! However, you can use it anywhere else.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,9 +191,19 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
||||
fn statement_like(&mut self) {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
if self.mode != Mode::Fn {
|
||||
span_err!(self.tcx.sess, self.span, E0016,
|
||||
"blocks in {}s are limited to items and tail expressions",
|
||||
self.mode);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.span,
|
||||
E0016,
|
||||
"blocks in {}s are limited to items and tail expressions",
|
||||
self.mode
|
||||
);
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("Blocks in constants may only contain items (such as constant, function \
|
||||
definition, etc...) and a tail expression.");
|
||||
err.help("To avoid it, you have to replace the non-item object.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,9 +496,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
}
|
||||
|
||||
if self.mode == Mode::Const || self.mode == Mode::ConstFn {
|
||||
span_err!(self.tcx.sess, self.span, E0013,
|
||||
"{}s cannot refer to statics, use \
|
||||
a constant instead", self.mode);
|
||||
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
|
||||
"{}s cannot refer to statics, use \
|
||||
a constant instead", self.mode);
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"Static and const variables can refer to other const variables. But a \
|
||||
const variable cannot refer to a static variable."
|
||||
);
|
||||
err.help(
|
||||
"To fix this, the value can be extracted as a const and then used."
|
||||
);
|
||||
}
|
||||
err.emit()
|
||||
}
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
@ -497,13 +529,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
if let ty::TyRawPtr(_) = base_ty.sty {
|
||||
this.add(Qualif::NOT_CONST);
|
||||
if this.mode != Mode::Fn {
|
||||
struct_span_err!(this.tcx.sess,
|
||||
this.span, E0396,
|
||||
let mut err = struct_span_err!(
|
||||
this.tcx.sess,
|
||||
this.span,
|
||||
E0396,
|
||||
"raw pointers cannot be dereferenced in {}s",
|
||||
this.mode)
|
||||
.span_label(this.span,
|
||||
"dereference of raw pointer in constant")
|
||||
.emit();
|
||||
this.mode
|
||||
);
|
||||
err.span_label(this.span,
|
||||
"dereference of raw pointer in constant");
|
||||
if this.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"The value behind a raw pointer can't be determined \
|
||||
at compile-time (or even link-time), which means it \
|
||||
can't be used in a constant expression."
|
||||
);
|
||||
err.help("A possible fix is to dereference your pointer \
|
||||
at some point in run-time.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -622,12 +666,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
if !allow {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
if self.mode != Mode::Fn {
|
||||
struct_span_err!(self.tcx.sess, self.span, E0017,
|
||||
"references in {}s may only refer \
|
||||
to immutable values", self.mode)
|
||||
.span_label(self.span, format!("{}s require immutable values",
|
||||
self.mode))
|
||||
.emit();
|
||||
let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
|
||||
"references in {}s may only refer \
|
||||
to immutable values", self.mode);
|
||||
err.span_label(self.span, format!("{}s require immutable values",
|
||||
self.mode));
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("References in statics and constants may only refer to \
|
||||
immutable values.\n\n\
|
||||
Statics are shared everywhere, and if they refer to \
|
||||
mutable data one might violate memory safety since \
|
||||
holding multiple mutable references to shared data is \
|
||||
not allowed.\n\n\
|
||||
If you really want global mutable state, try using \
|
||||
static mut or a global UnsafeCell.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -668,9 +722,42 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
(CastTy::FnPtr, CastTy::Int(_)) => {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
if self.mode != Mode::Fn {
|
||||
span_err!(self.tcx.sess, self.span, E0018,
|
||||
"raw pointers cannot be cast to integers in {}s",
|
||||
self.mode);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.span,
|
||||
E0018,
|
||||
"raw pointers cannot be cast to integers in {}s",
|
||||
self.mode
|
||||
);
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("\
|
||||
The value of static and constant integers must be known at compile time. You can't cast a pointer \
|
||||
to an integer because the address of a pointer can vary.
|
||||
|
||||
For example, if you write:
|
||||
|
||||
```
|
||||
static MY_STATIC: u32 = 42;
|
||||
static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
|
||||
static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
|
||||
```
|
||||
|
||||
Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However, the address can change \
|
||||
when the program is linked, as well as change between different executions due to ASLR, and many \
|
||||
linkers would not be able to calculate the value of `WHAT`.
|
||||
|
||||
On the other hand, static and constant pointers can point either to a known numeric address or to \
|
||||
the address of a symbol.
|
||||
|
||||
```
|
||||
static MY_STATIC: u32 = 42;
|
||||
static MY_STATIC_ADDR: &'static u32 = &MY_STATIC;
|
||||
const CONST_ADDR: *const u8 = 0x5f3759df as *const u8;
|
||||
```
|
||||
|
||||
This does not pose a problem by itself because they can't be accessed directly.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -701,10 +788,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
Rvalue::NullaryOp(NullOp::Box, _) => {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
if self.mode != Mode::Fn {
|
||||
struct_span_err!(self.tcx.sess, self.span, E0010,
|
||||
"allocations are not allowed in {}s", self.mode)
|
||||
.span_label(self.span, format!("allocation not allowed in {}s", self.mode))
|
||||
.emit();
|
||||
let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
|
||||
"allocations are not allowed in {}s", self.mode);
|
||||
err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"The value of statics and constants must be known at compile time, \
|
||||
and they live for the entire lifetime of a program. Creating a boxed \
|
||||
value allocates memory on the heap at runtime, and therefore cannot \
|
||||
be done at compile time."
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,9 +1025,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
// Avoid a generic error for other uses of arguments.
|
||||
if self.qualif.intersects(Qualif::FN_ARGUMENT) {
|
||||
let decl = &self.mir.local_decls[index];
|
||||
span_err!(self.tcx.sess, decl.source_info.span, E0022,
|
||||
"arguments of constant functions can only \
|
||||
be immutable by-value bindings");
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
decl.source_info.span,
|
||||
E0022,
|
||||
"arguments of constant functions can only be immutable by-value bindings"
|
||||
);
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("Constant functions are not allowed to mutate anything. Thus, \
|
||||
binding to an argument with a mutable pattern is not allowed.");
|
||||
err.note("Remove any mutable bindings from the argument list to fix this \
|
||||
error. In case you need to mutate the argument, try lazily \
|
||||
initializing a global variable instead of using a const fn, or \
|
||||
refactoring the code to a functional style to avoid mutation if \
|
||||
possible.");
|
||||
}
|
||||
err.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -237,10 +237,20 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
|
||||
Ok(Ordering::Less) |
|
||||
Ok(Ordering::Equal) => {}
|
||||
Ok(Ordering::Greater) => {
|
||||
struct_span_err!(self.tcx.sess, start.span, E0030,
|
||||
"lower range bound must be less than or equal to upper")
|
||||
.span_label(start.span, "lower bound larger than upper bound")
|
||||
.emit();
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
start.span,
|
||||
E0030,
|
||||
"lower range bound must be less than or equal to upper"
|
||||
);
|
||||
err.span_label(start.span, "lower bound larger than upper bound");
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("When matching against a range, the compiler verifies that \
|
||||
the range is non-empty. Range patterns include both \
|
||||
end-points, so this is equivalent to requiring the start of \
|
||||
the range to be less than or equal to the end of the range.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
Err(ErrorReported) => {}
|
||||
}
|
||||
|
@ -214,12 +214,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
end.span
|
||||
};
|
||||
|
||||
struct_span_err!(tcx.sess, span, E0029,
|
||||
"only char and numeric types are allowed in range patterns")
|
||||
.span_label(span, "ranges require char or numeric types")
|
||||
.note(&format!("start type: {}", self.ty_to_string(lhs_ty)))
|
||||
.note(&format!("end type: {}", self.ty_to_string(rhs_ty)))
|
||||
.emit();
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0029,
|
||||
"only char and numeric types are allowed in range patterns"
|
||||
);
|
||||
err.span_label(span, "ranges require char or numeric types");
|
||||
err.note(&format!("start type: {}", self.ty_to_string(lhs_ty)));
|
||||
err.note(&format!("end type: {}", self.ty_to_string(rhs_ty)));
|
||||
if tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"In a match expression, only numbers and characters can be matched \
|
||||
against a range. This is because the compiler checks that the range \
|
||||
is non-empty at compile-time, and is unable to evaluate arbitrary \
|
||||
comparison functions. If you want to capture values of an orderable \
|
||||
type between two end-points, you can use a guard."
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -505,10 +518,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// This is "x = SomeTrait" being reduced from
|
||||
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
|
||||
let type_str = self.ty_to_string(expected);
|
||||
struct_span_err!(self.tcx.sess, span, E0033,
|
||||
"type `{}` cannot be dereferenced", type_str)
|
||||
.span_label(span, format!("type `{}` cannot be dereferenced", type_str))
|
||||
.emit();
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0033,
|
||||
"type `{}` cannot be dereferenced",
|
||||
type_str
|
||||
);
|
||||
err.span_label(span, format!("type `{}` cannot be dereferenced", type_str));
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("\
|
||||
This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
|
||||
pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \
|
||||
this type has no compile-time size. Therefore, all accesses to trait types must be through \
|
||||
pointers. If you encounter this error you should try to avoid dereferencing the pointer.
|
||||
|
||||
You can read more about trait objects in the Trait Objects section of the Reference: \
|
||||
https://doc.rust-lang.org/reference/types.html#trait-objects");
|
||||
}
|
||||
err.emit();
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -881,17 +909,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.field_ty(span, f, substs)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
struct_span_err!(tcx.sess, span, E0026,
|
||||
"{} `{}` does not have a field named `{}`",
|
||||
kind_name,
|
||||
tcx.item_path_str(variant.did),
|
||||
field.name)
|
||||
.span_label(span,
|
||||
format!("{} `{}` does not have field `{}`",
|
||||
kind_name,
|
||||
tcx.item_path_str(variant.did),
|
||||
field.name))
|
||||
.emit();
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0026,
|
||||
"{} `{}` does not have a field named `{}`",
|
||||
kind_name,
|
||||
tcx.item_path_str(variant.did),
|
||||
field.name
|
||||
);
|
||||
err.span_label(span,
|
||||
format!("{} `{}` does not have field `{}`",
|
||||
kind_name,
|
||||
tcx.item_path_str(variant.did),
|
||||
field.name));
|
||||
if tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"This error indicates that a struct pattern attempted to \
|
||||
extract a non-existent field from a struct. Struct fields \
|
||||
are identified by the name used before the colon : so struct \
|
||||
patterns should resemble the declaration of the struct type \
|
||||
being matched.\n\n\
|
||||
If you are using shorthand field patterns but want to refer \
|
||||
to the struct field by a different name, you should rename \
|
||||
it explicitly."
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
|
||||
tcx.types.err
|
||||
})
|
||||
@ -927,6 +971,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
if variant.ctor_kind == CtorKind::Fn {
|
||||
diag.note("trying to match a tuple variant with a struct variant pattern");
|
||||
}
|
||||
if tcx.sess.teach(&diag.get_code().unwrap()) {
|
||||
diag.note(
|
||||
"This error indicates that a pattern for a struct fails to specify a \
|
||||
sub-pattern for every one of the struct's fields. Ensure that each field \
|
||||
from the struct's definition is mentioned in the pattern, or use `..` to \
|
||||
ignore unwanted fields."
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user