@@ -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
@@ -475,9 +497,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
475497 }
476498
477499 if self . mode == Mode :: Const || self . mode == Mode :: ConstFn {
478- span_err ! ( self . tcx. sess, self . span, E0013 ,
479- "{}s cannot refer to statics, use \
480- a constant instead", self . mode) ;
500+ let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0013 ,
501+ "{}s cannot refer to statics, use \
502+ a constant instead", self . mode) ;
503+ if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
504+ err. note (
505+ "Static and const variables can refer to other const variables. But a \
506+ const variable cannot refer to a static variable."
507+ ) ;
508+ err. help (
509+ "To fix this, the value can be extracted as a const and then used."
510+ ) ;
511+ }
512+ err. emit ( )
481513 }
482514 }
483515 Place :: Projection ( ref proj) => {
@@ -498,13 +530,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
498530 if let ty:: TyRawPtr ( _) = base_ty. sty {
499531 this. add ( Qualif :: NOT_CONST ) ;
500532 if this. mode != Mode :: Fn {
501- struct_span_err ! ( this. tcx. sess,
502- this. span, E0396 ,
533+ let mut err = struct_span_err ! (
534+ this. tcx. sess,
535+ this. span,
536+ E0396 ,
503537 "raw pointers cannot be dereferenced in {}s" ,
504- this. mode)
505- . span_label ( this. span ,
506- "dereference of raw pointer in constant" )
507- . emit ( ) ;
538+ this. mode
539+ ) ;
540+ err. span_label ( this. span ,
541+ "dereference of raw pointer in constant" ) ;
542+ if this. tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
543+ err. note (
544+ "The value behind a raw pointer can't be determined \
545+ at compile-time (or even link-time), which means it \
546+ can't be used in a constant expression."
547+ ) ;
548+ err. help ( "A possible fix is to dereference your pointer \
549+ at some point in run-time.") ;
550+ }
551+ err. emit ( ) ;
508552 }
509553 }
510554 }
@@ -623,12 +667,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
623667 if !allow {
624668 self . add ( Qualif :: NOT_CONST ) ;
625669 if self . mode != Mode :: Fn {
626- struct_span_err ! ( self . tcx. sess, self . span, E0017 ,
627- "references in {}s may only refer \
628- to immutable values", self . mode)
629- . span_label ( self . span , format ! ( "{}s require immutable values" ,
630- self . mode) )
631- . emit ( ) ;
670+ let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0017 ,
671+ "references in {}s may only refer \
672+ to immutable values", self . mode) ;
673+ err. span_label ( self . span , format ! ( "{}s require immutable values" ,
674+ self . mode) ) ;
675+ if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
676+ err. note ( "References in statics and constants may only refer to \
677+ immutable values.\n \n \
678+ Statics are shared everywhere, and if they refer to \
679+ mutable data one might violate memory safety since \
680+ holding multiple mutable references to shared data is \
681+ not allowed.\n \n \
682+ If you really want global mutable state, try using \
683+ static mut or a global UnsafeCell.") ;
684+ }
685+ err. emit ( ) ;
632686 }
633687 }
634688 } else {
@@ -669,9 +723,42 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
669723 ( CastTy :: FnPtr , CastTy :: Int ( _) ) => {
670724 self . add ( Qualif :: NOT_CONST ) ;
671725 if self . mode != Mode :: Fn {
672- span_err ! ( self . tcx. sess, self . span, E0018 ,
673- "raw pointers cannot be cast to integers in {}s" ,
674- self . mode) ;
726+ let mut err = struct_span_err ! (
727+ self . tcx. sess,
728+ self . span,
729+ E0018 ,
730+ "raw pointers cannot be cast to integers in {}s" ,
731+ self . mode
732+ ) ;
733+ if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
734+ err. note ( "\
735+ The value of static and constant integers must be known at compile time. You can't cast a pointer \
736+ to an integer because the address of a pointer can vary.
737+
738+ For example, if you write:
739+
740+ ```
741+ static MY_STATIC: u32 = 42;
742+ static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
743+ static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
744+ ```
745+
746+ Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However, the address can change \
747+ when the program is linked, as well as change between different executions due to ASLR, and many \
748+ linkers would not be able to calculate the value of `WHAT`.
749+
750+ On the other hand, static and constant pointers can point either to a known numeric address or to \
751+ the address of a symbol.
752+
753+ ```
754+ static MY_STATIC: u32 = 42;
755+ static MY_STATIC_ADDR: &'static u32 = &MY_STATIC;
756+ const CONST_ADDR: *const u8 = 0x5f3759df as *const u8;
757+ ```
758+
759+ This does not pose a problem by itself because they can't be accessed directly." ) ;
760+ }
761+ err. emit ( ) ;
675762 }
676763 }
677764 _ => { }
@@ -702,10 +789,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
702789 Rvalue :: NullaryOp ( NullOp :: Box , _) => {
703790 self . add ( Qualif :: NOT_CONST ) ;
704791 if self . mode != Mode :: Fn {
705- struct_span_err ! ( self . tcx. sess, self . span, E0010 ,
706- "allocations are not allowed in {}s" , self . mode)
707- . span_label ( self . span , format ! ( "allocation not allowed in {}s" , self . mode) )
708- . emit ( ) ;
792+ let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0010 ,
793+ "allocations are not allowed in {}s" , self . mode) ;
794+ err. span_label ( self . span , format ! ( "allocation not allowed in {}s" , self . mode) ) ;
795+ if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
796+ err. note (
797+ "The value of statics and constants must be known at compile time, \
798+ and they live for the entire lifetime of a program. Creating a boxed \
799+ value allocates memory on the heap at runtime, and therefore cannot \
800+ be done at compile time."
801+ ) ;
802+ }
803+ err. emit ( ) ;
709804 }
710805 }
711806
@@ -931,9 +1026,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
9311026 // Avoid a generic error for other uses of arguments.
9321027 if self . qualif . intersects ( Qualif :: FN_ARGUMENT ) {
9331028 let decl = & self . mir . local_decls [ index] ;
934- span_err ! ( self . tcx. sess, decl. source_info. span, E0022 ,
935- "arguments of constant functions can only \
936- be immutable by-value bindings") ;
1029+ let mut err = struct_span_err ! (
1030+ self . tcx. sess,
1031+ decl. source_info. span,
1032+ E0022 ,
1033+ "arguments of constant functions can only be immutable by-value bindings"
1034+ ) ;
1035+ if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
1036+ err. note ( "Constant functions are not allowed to mutate anything. Thus, \
1037+ binding to an argument with a mutable pattern is not allowed.") ;
1038+ err. note ( "Remove any mutable bindings from the argument list to fix this \
1039+ error. In case you need to mutate the argument, try lazily \
1040+ initializing a global variable instead of using a const fn, or \
1041+ refactoring the code to a functional style to avoid mutation if \
1042+ possible.") ;
1043+ }
1044+ err. emit ( ) ;
9371045 return ;
9381046 }
9391047 }
0 commit comments