@@ -170,18 +170,40 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
170
170
fn not_const ( & mut self ) {
171
171
self . add ( Qualif :: NOT_CONST ) ;
172
172
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 ( ) ;
175
187
}
176
188
}
177
189
178
190
/// Error about extra statements in a constant.
179
191
fn statement_like ( & mut self ) {
180
192
self . add ( Qualif :: NOT_CONST ) ;
181
193
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 ( ) ;
185
207
}
186
208
}
187
209
@@ -475,9 +497,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
475
497
}
476
498
477
499
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 ( )
481
513
}
482
514
}
483
515
Place :: Projection ( ref proj) => {
@@ -498,13 +530,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
498
530
if let ty:: TyRawPtr ( _) = base_ty. sty {
499
531
this. add ( Qualif :: NOT_CONST ) ;
500
532
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 ,
503
537
"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 ( ) ;
508
552
}
509
553
}
510
554
}
@@ -623,12 +667,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
623
667
if !allow {
624
668
self . add ( Qualif :: NOT_CONST ) ;
625
669
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 ( ) ;
632
686
}
633
687
}
634
688
} else {
@@ -669,9 +723,42 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
669
723
( CastTy :: FnPtr , CastTy :: Int ( _) ) => {
670
724
self . add ( Qualif :: NOT_CONST ) ;
671
725
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 ( ) ;
675
762
}
676
763
}
677
764
_ => { }
@@ -702,10 +789,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
702
789
Rvalue :: NullaryOp ( NullOp :: Box , _) => {
703
790
self . add ( Qualif :: NOT_CONST ) ;
704
791
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 ( ) ;
709
804
}
710
805
}
711
806
@@ -931,9 +1026,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
931
1026
// Avoid a generic error for other uses of arguments.
932
1027
if self . qualif . intersects ( Qualif :: FN_ARGUMENT ) {
933
1028
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 ( ) ;
937
1045
return ;
938
1046
}
939
1047
}
0 commit comments