@@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag;
1616use rustc_session:: lint:: builtin:: UNEXPECTED_CFGS ;
1717use rustc_session:: parse:: feature_err;
1818use rustc_session:: { RustcVersion , Session } ;
19- use rustc_span:: Span ;
2019use rustc_span:: hygiene:: Transparency ;
2120use rustc_span:: symbol:: { Symbol , kw, sym} ;
21+ use rustc_span:: { DUMMY_SP , Span } ;
2222
2323use crate :: fluent_generated;
2424use crate :: session_diagnostics:: { self , IncorrectReprFormatGenericCause } ;
@@ -92,7 +92,13 @@ impl Stability {
9292#[ derive( HashStable_Generic ) ]
9393pub struct ConstStability {
9494 pub level : StabilityLevel ,
95- pub feature : Symbol ,
95+ /// This can be `None` for functions that are not even const-unstable, but
96+ /// are tracked here for the purpose of `safe_to_expose_on_stable`.
97+ pub feature : Option < Symbol > ,
98+ /// A function that is marked as "safe to expose on stable" must not use any unstable const
99+ /// language features or intrinsics, and all the functions it calls must also be safe to expose
100+ /// on stable. If `level` is `Stable`, this must be `true`.
101+ pub safe_to_expose_on_stable : bool ,
96102 /// whether the function has a `#[rustc_promotable]` attribute
97103 pub promotable : bool ,
98104}
@@ -275,10 +281,12 @@ pub fn find_const_stability(
275281) -> Option < ( ConstStability , Span ) > {
276282 let mut const_stab: Option < ( ConstStability , Span ) > = None ;
277283 let mut promotable = false ;
284+ let mut const_stable_indirect = false ;
278285
279286 for attr in attrs {
280287 match attr. name_or_empty ( ) {
281288 sym:: rustc_promotable => promotable = true ,
289+ sym:: rustc_const_stable_indirect => const_stable_indirect = true ,
282290 sym:: rustc_const_unstable => {
283291 if const_stab. is_some ( ) {
284292 sess. dcx ( )
@@ -287,8 +295,15 @@ pub fn find_const_stability(
287295 }
288296
289297 if let Some ( ( feature, level) ) = parse_unstability ( sess, attr) {
290- const_stab =
291- Some ( ( ConstStability { level, feature, promotable : false } , attr. span ) ) ;
298+ const_stab = Some ( (
299+ ConstStability {
300+ level,
301+ feature : Some ( feature) ,
302+ safe_to_expose_on_stable : false ,
303+ promotable : false ,
304+ } ,
305+ attr. span ,
306+ ) ) ;
292307 }
293308 }
294309 sym:: rustc_const_stable => {
@@ -298,15 +313,22 @@ pub fn find_const_stability(
298313 break ;
299314 }
300315 if let Some ( ( feature, level) ) = parse_stability ( sess, attr) {
301- const_stab =
302- Some ( ( ConstStability { level, feature, promotable : false } , attr. span ) ) ;
316+ const_stab = Some ( (
317+ ConstStability {
318+ level,
319+ feature : Some ( feature) ,
320+ safe_to_expose_on_stable : true ,
321+ promotable : false ,
322+ } ,
323+ attr. span ,
324+ ) ) ;
303325 }
304326 }
305327 _ => { }
306328 }
307329 }
308330
309- // Merge the const-unstable info into the stability info
331+ // Merge promotable and not_exposed_on_stable into stability info
310332 if promotable {
311333 match & mut const_stab {
312334 Some ( ( stab, _) ) => stab. promotable = promotable,
@@ -317,6 +339,33 @@ pub fn find_const_stability(
317339 }
318340 }
319341 }
342+ if const_stable_indirect {
343+ match & mut const_stab {
344+ Some ( ( stab, _) ) => {
345+ if stab. is_const_unstable ( ) {
346+ stab. safe_to_expose_on_stable = true ;
347+ } else {
348+ _ = sess. dcx ( ) . emit_err ( session_diagnostics:: RustcConstStableIndirectPairing {
349+ span : item_sp,
350+ } )
351+ }
352+ }
353+ _ => {
354+ let c = ConstStability {
355+ feature : None ,
356+ safe_to_expose_on_stable : true ,
357+ promotable : false ,
358+ level : StabilityLevel :: Unstable {
359+ reason : UnstableReason :: Default ,
360+ issue : None ,
361+ is_soft : false ,
362+ implied_by : None ,
363+ } ,
364+ } ;
365+ const_stab = Some ( ( c, DUMMY_SP ) ) ;
366+ }
367+ }
368+ }
320369
321370 const_stab
322371}
0 commit comments