77//! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
88//! through, but errors for structured control flow in a `const` should be emitted here.
99
10+ use rustc_attr as attr;
1011use rustc_errors:: struct_span_err;
1112use rustc_hir as hir;
1213use rustc_hir:: def_id:: LocalDefId ;
@@ -70,35 +71,63 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
7071struct CheckConstVisitor < ' tcx > {
7172 tcx : TyCtxt < ' tcx > ,
7273 const_kind : Option < hir:: ConstContext > ,
74+ def_id : Option < DefId > ,
7375}
7476
7577impl < ' tcx > CheckConstVisitor < ' tcx > {
7678 fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
77- CheckConstVisitor { tcx, const_kind : None }
79+ CheckConstVisitor { tcx, const_kind : None , def_id : None }
7880 }
7981
8082 /// Emits an error when an unsupported expression is found in a const context.
8183 fn const_check_violated ( & self , expr : NonConstExpr , span : Span ) {
82- let features = self . tcx . features ( ) ;
84+ let Self { tcx, def_id, const_kind } = * self ;
85+
86+ let features = tcx. features ( ) ;
8387 let required_gates = expr. required_feature_gates ( ) ;
88+
89+ let is_feature_allowed = |feature_gate| {
90+ // All features require that the corresponding gate be enabled,
91+ // even if the function has `#[allow_internal_unstable(the_gate)]`.
92+ if !tcx. features ( ) . enabled ( feature_gate) {
93+ return false ;
94+ }
95+
96+ // If `def_id` is `None`, we don't need to consider stability attributes.
97+ let def_id = match def_id {
98+ Some ( x) => x,
99+ None => return true ,
100+ } ;
101+
102+ // If this crate is not using stability attributes, or this function is not claiming to be a
103+ // stable `const fn`, that is all that is required.
104+ if !tcx. features ( ) . staged_api || tcx. has_attr ( def_id, sym:: rustc_const_unstable) {
105+ return true ;
106+ }
107+
108+ // However, we cannot allow stable `const fn`s to use unstable features without an explicit
109+ // opt-in via `allow_internal_unstable`.
110+ attr:: allow_internal_unstable ( & tcx. get_attrs ( def_id) , & tcx. sess . diagnostic ( ) )
111+ . map_or ( false , |mut features| features. any ( |name| name == feature_gate) )
112+ } ;
113+
84114 match required_gates {
85115 // Don't emit an error if the user has enabled the requisite feature gates.
86- Some ( gates) if gates. iter ( ) . all ( | & g| features . enabled ( g ) ) => return ,
116+ Some ( gates) if gates. iter ( ) . copied ( ) . all ( is_feature_allowed ) => return ,
87117
88118 // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
89119 // corresponding feature gate. This encourages nightly users to use feature gates when
90120 // possible.
91- None if self . tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you => {
92- self . tcx . sess . span_warn ( span, "skipping const checks" ) ;
121+ None if tcx. sess . opts . debugging_opts . unleash_the_miri_inside_of_you => {
122+ tcx. sess . span_warn ( span, "skipping const checks" ) ;
93123 return ;
94124 }
95125
96126 _ => { }
97127 }
98128
99- let const_kind = self
100- . const_kind
101- . expect ( "`const_check_violated` may only be called inside a const context" ) ;
129+ let const_kind =
130+ const_kind. expect ( "`const_check_violated` may only be called inside a const context" ) ;
102131
103132 let msg = format ! ( "{} is not allowed in a `{}`" , expr. name( ) , const_kind. keyword_name( ) ) ;
104133
@@ -107,10 +136,10 @@ impl<'tcx> CheckConstVisitor<'tcx> {
107136 required_gates. iter ( ) . copied ( ) . filter ( |& g| !features. enabled ( g) ) . collect ( ) ;
108137
109138 match missing_gates. as_slice ( ) {
110- & [ ] => struct_span_err ! ( self . tcx. sess, span, E0744 , "{}" , msg) . emit ( ) ,
139+ & [ ] => struct_span_err ! ( tcx. sess, span, E0744 , "{}" , msg) . emit ( ) ,
111140
112141 & [ missing_primary, ref missing_secondary @ ..] => {
113- let mut err = feature_err ( & self . tcx . sess . parse_sess , missing_primary, span, & msg) ;
142+ let mut err = feature_err ( & tcx. sess . parse_sess , missing_primary, span, & msg) ;
114143
115144 // If multiple feature gates would be required to enable this expression, include
116145 // them as help messages. Don't emit a separate error for each missing feature gate.
@@ -133,10 +162,18 @@ impl<'tcx> CheckConstVisitor<'tcx> {
133162 }
134163
135164 /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
136- fn recurse_into ( & mut self , kind : Option < hir:: ConstContext > , f : impl FnOnce ( & mut Self ) ) {
165+ fn recurse_into (
166+ & mut self ,
167+ kind : Option < hir:: ConstContext > ,
168+ def_id : Option < DefId > ,
169+ f : impl FnOnce ( & mut Self ) ,
170+ ) {
171+ let parent_def_id = self . def_id ;
137172 let parent_kind = self . const_kind ;
173+ self . def_id = def_id;
138174 self . const_kind = kind;
139175 f ( self ) ;
176+ self . def_id = parent_def_id;
140177 self . const_kind = parent_kind;
141178 }
142179}
@@ -150,13 +187,13 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
150187
151188 fn visit_anon_const ( & mut self , anon : & ' tcx hir:: AnonConst ) {
152189 let kind = Some ( hir:: ConstContext :: Const ) ;
153- self . recurse_into ( kind, |this| intravisit:: walk_anon_const ( this, anon) ) ;
190+ self . recurse_into ( kind, None , |this| intravisit:: walk_anon_const ( this, anon) ) ;
154191 }
155192
156193 fn visit_body ( & mut self , body : & ' tcx hir:: Body < ' tcx > ) {
157194 let owner = self . tcx . hir ( ) . body_owner_def_id ( body. id ( ) ) ;
158195 let kind = self . tcx . hir ( ) . body_const_context ( owner) ;
159- self . recurse_into ( kind, |this| intravisit:: walk_body ( this, body) ) ;
196+ self . recurse_into ( kind, Some ( owner . to_def_id ( ) ) , |this| intravisit:: walk_body ( this, body) ) ;
160197 }
161198
162199 fn visit_expr ( & mut self , e : & ' tcx hir:: Expr < ' tcx > ) {
0 commit comments