@@ -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 }
0 commit comments