@@ -918,20 +918,27 @@ struct Context<'a> {
918
918
}
919
919
920
920
macro_rules! gate_feature_fn {
921
- ( $cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => { {
922
- let ( cx, has_feature, span, name, explain) = ( $cx, $has_feature, $span, $name, $explain) ;
921
+ ( $cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => { {
922
+ let ( cx, has_feature, span,
923
+ name, explain, level) = ( $cx, $has_feature, $span, $name, $explain, $level) ;
923
924
let has_feature: bool = has_feature( & $cx. features) ;
924
925
debug!( "gate_feature(feature = {:?}, span = {:?}); has? {}" , name, span, has_feature) ;
925
926
if !has_feature && !span. allows_unstable( ) {
926
- emit_feature_err( cx. parse_sess, name, span, GateIssue :: Language , explain) ;
927
+ leveled_feature_err( cx. parse_sess, name, span, GateIssue :: Language , explain, level)
928
+ . emit( ) ;
927
929
}
928
930
} }
929
931
}
930
932
931
933
macro_rules! gate_feature {
932
934
( $cx: expr, $feature: ident, $span: expr, $explain: expr) => {
933
- gate_feature_fn!( $cx, |x: & Features | x. $feature, $span, stringify!( $feature) , $explain)
934
- }
935
+ gate_feature_fn!( $cx, |x: & Features | x. $feature, $span,
936
+ stringify!( $feature) , $explain, GateStrength :: Hard )
937
+ } ;
938
+ ( $cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
939
+ gate_feature_fn!( $cx, |x: & Features | x. $feature, $span,
940
+ stringify!( $feature) , $explain, $level)
941
+ } ;
935
942
}
936
943
937
944
impl < ' a > Context < ' a > {
@@ -941,7 +948,7 @@ impl<'a> Context<'a> {
941
948
for & ( n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
942
949
if name == n {
943
950
if let Gated ( _, name, desc, ref has_feature) = * gateage {
944
- gate_feature_fn ! ( self , has_feature, attr. span, name, desc) ;
951
+ gate_feature_fn ! ( self , has_feature, attr. span, name, desc, GateStrength :: Hard ) ;
945
952
}
946
953
debug ! ( "check_attribute: {:?} is builtin, {:?}, {:?}" , attr. path, ty, gateage) ;
947
954
return ;
@@ -1011,24 +1018,42 @@ pub enum GateIssue {
1011
1018
Library ( Option < u32 > )
1012
1019
}
1013
1020
1021
+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
1022
+ pub enum GateStrength {
1023
+ /// A hard error. (Most feature gates should use this.)
1024
+ Hard ,
1025
+ /// Only a warning. (Use this only as backwards-compatibility demands.)
1026
+ Soft ,
1027
+ }
1028
+
1014
1029
pub fn emit_feature_err ( sess : & ParseSess , feature : & str , span : Span , issue : GateIssue ,
1015
1030
explain : & str ) {
1016
1031
feature_err ( sess, feature, span, issue, explain) . emit ( ) ;
1017
1032
}
1018
1033
1019
1034
pub fn feature_err < ' a > ( sess : & ' a ParseSess , feature : & str , span : Span , issue : GateIssue ,
1020
1035
explain : & str ) -> DiagnosticBuilder < ' a > {
1036
+ leveled_feature_err ( sess, feature, span, issue, explain, GateStrength :: Hard )
1037
+ }
1038
+
1039
+ fn leveled_feature_err < ' a > ( sess : & ' a ParseSess , feature : & str , span : Span , issue : GateIssue ,
1040
+ explain : & str , level : GateStrength ) -> DiagnosticBuilder < ' a > {
1021
1041
let diag = & sess. span_diagnostic ;
1022
1042
1023
1043
let issue = match issue {
1024
1044
GateIssue :: Language => find_lang_feature_issue ( feature) ,
1025
1045
GateIssue :: Library ( lib) => lib,
1026
1046
} ;
1027
1047
1028
- let mut err = if let Some ( n) = issue {
1029
- diag . struct_span_err ( span , & format ! ( "{} (see issue #{})" , explain, n) )
1048
+ let explanation = if let Some ( n) = issue {
1049
+ format ! ( "{} (see issue #{})" , explain, n)
1030
1050
} else {
1031
- diag. struct_span_err ( span, explain)
1051
+ explain. to_owned ( )
1052
+ } ;
1053
+
1054
+ let mut err = match level {
1055
+ GateStrength :: Hard => diag. struct_span_err ( span, & explanation) ,
1056
+ GateStrength :: Soft => diag. struct_span_warn ( span, & explanation) ,
1032
1057
} ;
1033
1058
1034
1059
// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
@@ -1038,7 +1063,15 @@ pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga
1038
1063
feature) ) ;
1039
1064
}
1040
1065
1066
+ // If we're on stable and only emitting a "soft" warning, add a note to
1067
+ // clarify that the feature isn't "on" (rather than being on but
1068
+ // warning-worthy).
1069
+ if !sess. unstable_features . is_nightly_build ( ) && level == GateStrength :: Soft {
1070
+ err. help ( "a nightly build of the compiler is required to enable this feature" ) ;
1071
+ }
1072
+
1041
1073
err
1074
+
1042
1075
}
1043
1076
1044
1077
const EXPLAIN_BOX_SYNTAX : & ' static str =
@@ -1095,6 +1128,12 @@ macro_rules! gate_feature_post {
1095
1128
if !span. allows_unstable( ) {
1096
1129
gate_feature!( cx. context, $feature, span, $explain)
1097
1130
}
1131
+ } } ;
1132
+ ( $cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { {
1133
+ let ( cx, span) = ( $cx, $span) ;
1134
+ if !span. allows_unstable( ) {
1135
+ gate_feature!( cx. context, $feature, span, $explain, $level)
1136
+ }
1098
1137
} }
1099
1138
}
1100
1139
@@ -1239,7 +1278,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1239
1278
}
1240
1279
if attr:: contains_name ( & i. attrs [ ..] , "must_use" ) {
1241
1280
gate_feature_post ! ( & self , fn_must_use, i. span,
1242
- "`#[must_use]` on functions is experimental" ) ;
1281
+ "`#[must_use]` on functions is experimental" ,
1282
+ GateStrength :: Soft ) ;
1243
1283
}
1244
1284
}
1245
1285
0 commit comments