@@ -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
@@ -474,9 +496,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
474
496
}
475
497
476
498
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 ( )
480
512
}
481
513
}
482
514
Place :: Projection ( ref proj) => {
@@ -497,13 +529,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
497
529
if let ty:: TyRawPtr ( _) = base_ty. sty {
498
530
this. add ( Qualif :: NOT_CONST ) ;
499
531
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 ,
502
536
"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 ( ) ;
507
551
}
508
552
}
509
553
}
@@ -622,12 +666,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
622
666
if !allow {
623
667
self . add ( Qualif :: NOT_CONST ) ;
624
668
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 ( ) ;
631
685
}
632
686
}
633
687
} else {
@@ -668,9 +722,42 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
668
722
( CastTy :: FnPtr , CastTy :: Int ( _) ) => {
669
723
self . add ( Qualif :: NOT_CONST ) ;
670
724
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 ( ) ;
674
761
}
675
762
}
676
763
_ => { }
@@ -701,10 +788,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
701
788
Rvalue :: NullaryOp ( NullOp :: Box , _) => {
702
789
self . add ( Qualif :: NOT_CONST ) ;
703
790
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 ( ) ;
708
803
}
709
804
}
710
805
@@ -930,9 +1025,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
930
1025
// Avoid a generic error for other uses of arguments.
931
1026
if self . qualif . intersects ( Qualif :: FN_ARGUMENT ) {
932
1027
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 ( ) ;
936
1044
return ;
937
1045
}
938
1046
}
0 commit comments