Skip to content

Add -Zteach documentation #47843

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions src/librustc/middle/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand Down
168 changes: 138 additions & 30 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,40 @@ 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();
}
}

/// Error about extra statements in a constant.
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();
}
}

Expand Down Expand Up @@ -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) => {
Expand All @@ -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();
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
}
}
_ => {}
Expand Down Expand Up @@ -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 \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the note code word wrap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't at the moment.

value allocates memory on the heap at runtime, and therefore cannot \
be done at compile time."
);
}
err.emit();
}
}

Expand Down Expand Up @@ -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;
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/librustc_passes/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {}
}
Expand Down
Loading