Skip to content

Commit 852271f

Browse files
committed
factor out some commonalities in the find_stability family of functions
the logic for adding unstable attrs gets a bit messier when supporting multiple instances thereof. this keeps that from being duplicated in 3 places.
1 parent 666d312 commit 852271f

File tree

1 file changed

+86
-104
lines changed

1 file changed

+86
-104
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 86 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -242,54 +242,40 @@ pub fn find_stability(
242242
attrs: &[Attribute],
243243
item_sp: Span,
244244
) -> Option<(Stability, Span)> {
245-
let mut stab: Option<(Stability, Span)> = None;
245+
let mut level: Option<(StabilityLevel, Span)> = None;
246246
let mut allowed_through_unstable_modules = false;
247247

248248
for attr in attrs {
249249
match attr.name_or_empty() {
250250
sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
251251
sym::unstable => {
252-
if stab.is_some() {
253-
sess.dcx()
254-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
252+
if try_add_unstability(sess, attr, &mut level).is_err() {
255253
break;
256254
}
257-
258-
if let Some(level) = parse_unstability(sess, attr) {
259-
stab = Some((Stability { level }, attr.span));
260-
}
261255
}
262256
sym::stable => {
263-
if stab.is_some() {
264-
sess.dcx()
265-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
257+
if try_add_stability(sess, attr, &mut level).is_err() {
266258
break;
267259
}
268-
if let Some(level) = parse_stability(sess, attr) {
269-
stab = Some((Stability { level }, attr.span));
270-
}
271260
}
272261
_ => {}
273262
}
274263
}
275264

276265
if allowed_through_unstable_modules {
277-
match &mut stab {
278-
Some((
279-
Stability {
280-
level: StabilityLevel::Stable { allowed_through_unstable_modules, .. },
281-
..
282-
},
283-
_,
284-
)) => *allowed_through_unstable_modules = true,
266+
match &mut level {
267+
Some((StabilityLevel::Stable { allowed_through_unstable_modules, .. }, _)) => {
268+
*allowed_through_unstable_modules = true
269+
}
285270
_ => {
286271
sess.dcx()
287272
.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
288273
}
289274
}
290275
}
291276

292-
stab
277+
let (level, stab_sp) = level?;
278+
Some((Stability { level }, stab_sp))
293279
}
294280

295281
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
@@ -303,104 +289,69 @@ pub fn find_const_stability(
303289
item_sp: Span,
304290
is_const_fn: bool,
305291
) -> Option<(ConstStability, Span)> {
306-
let mut const_stab: Option<(ConstStability, Span)> = None;
292+
let mut level: Option<(StabilityLevel, Span)> = None;
307293
let mut promotable = false;
308294
let mut const_stable_indirect = None;
309-
let const_stability_level = |level| match level {
310-
StabilityLevel::Unstable { unstables, .. } => ConstStabilityLevel::Unstable { unstables },
311-
StabilityLevel::Stable { since, .. } => ConstStabilityLevel::Stable { since },
312-
};
313295

314296
for attr in attrs {
315297
match attr.name_or_empty() {
316298
sym::rustc_promotable => promotable = true,
317299
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
318300
sym::rustc_const_unstable => {
319-
if const_stab.is_some() {
320-
sess.dcx()
321-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
301+
if try_add_unstability(sess, attr, &mut level).is_err() {
322302
break;
323303
}
324-
325-
if let Some(level) = parse_unstability(sess, attr) {
326-
const_stab = Some((
327-
ConstStability {
328-
level: const_stability_level(level),
329-
const_stable_indirect: false,
330-
promotable: false,
331-
},
332-
attr.span,
333-
));
334-
}
335304
}
336305
sym::rustc_const_stable => {
337-
if const_stab.is_some() {
338-
sess.dcx()
339-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
306+
if try_add_stability(sess, attr, &mut level).is_err() {
340307
break;
341308
}
342-
if let Some(level) = parse_stability(sess, attr) {
343-
const_stab = Some((
344-
ConstStability {
345-
level: const_stability_level(level),
346-
const_stable_indirect: false,
347-
promotable: false,
348-
},
349-
attr.span,
350-
));
351-
}
352309
}
353310
_ => {}
354311
}
355312
}
356313

357314
// Merge promotable and not_exposed_on_stable into stability info
358-
if promotable {
359-
match &mut const_stab {
360-
Some((stab, _)) => stab.promotable = promotable,
361-
_ => {
362-
_ = sess
363-
.dcx()
364-
.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp })
315+
let (level, stab_sp) = if let Some((level, stab_sp)) = level {
316+
match level {
317+
StabilityLevel::Unstable { unstables, .. } => {
318+
(ConstStabilityLevel::Unstable { unstables }, stab_sp)
365319
}
366-
}
367-
}
368-
if const_stable_indirect.is_some() {
369-
match &mut const_stab {
370-
Some((stab, _)) => {
371-
if stab.is_const_unstable() {
372-
stab.const_stable_indirect = true;
373-
} else {
374-
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
320+
StabilityLevel::Stable { since, .. } => {
321+
if const_stable_indirect.is_some() {
322+
sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
375323
span: item_sp,
376-
})
324+
});
377325
}
378-
}
379-
_ => {
380-
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
381-
// the `default_const_unstable` logic.
326+
(ConstStabilityLevel::Stable { since }, stab_sp)
382327
}
383328
}
384-
}
385-
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
386-
// fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
387-
// stability checks for them. We need to do this because the default for whether an unmarked
388-
// function enforces recursive stability differs between staged-api crates and force-unmarked
389-
// crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
390-
// enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
391-
// assume the function does not have recursive stability. All functions that *do* have recursive
392-
// stability must explicitly record this, and so that's what we do for all `const fn` in a
393-
// staged_api crate.
394-
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
395-
let c = ConstStability {
396-
level: ConstStabilityLevel::Implicit,
397-
const_stable_indirect: const_stable_indirect.is_some(),
398-
promotable: false,
399-
};
400-
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
401-
}
329+
} else {
330+
if promotable {
331+
sess.dcx().emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp });
332+
}
333+
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all
334+
// `const fn` get *some* marker, since we are a staged_api crate and therefore will do
335+
// recursive const stability checks for them. We need to do this because the default for
336+
// whether an unmarked function enforces recursive stability differs between staged-api
337+
// crates and force-unmarked crates: in force-unmarked crates, only functions *explicitly*
338+
// marked `const_stable_indirect` enforce recursive stability. Therefore when
339+
// `lookup_const_stability` is `None`, we have to assume the function does not have
340+
// recursive stability. All functions that *do* have recursive stability must explicitly
341+
// record this, and so that's what we do for all `const fn` in a staged_api crate.
342+
if is_const_fn || const_stable_indirect.is_some() {
343+
(ConstStabilityLevel::Implicit, const_stable_indirect.unwrap_or(DUMMY_SP))
344+
} else {
345+
return None;
346+
}
347+
};
402348

403-
const_stab
349+
let const_stab = ConstStability {
350+
level,
351+
const_stable_indirect: const_stable_indirect.is_some(),
352+
promotable,
353+
};
354+
Some((const_stab, stab_sp))
404355
}
405356

406357
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
@@ -409,23 +360,54 @@ pub fn find_body_stability(
409360
sess: &Session,
410361
attrs: &[Attribute],
411362
) -> Option<(DefaultBodyStability, Span)> {
412-
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
363+
let mut level: Option<(StabilityLevel, Span)> = None;
413364

414365
for attr in attrs {
415366
if attr.has_name(sym::rustc_default_body_unstable) {
416-
if body_stab.is_some() {
417-
sess.dcx()
418-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
367+
if try_add_unstability(sess, attr, &mut level).is_err() {
419368
break;
420369
}
421-
422-
if let Some(level) = parse_unstability(sess, attr) {
423-
body_stab = Some((DefaultBodyStability { level }, attr.span));
424-
}
425370
}
426371
}
427372

428-
body_stab
373+
let (level, stab_sp) = level?;
374+
Some((DefaultBodyStability { level }, stab_sp))
375+
}
376+
377+
/// Collects stability info from one `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
378+
/// attribute, `attr`. Emits an error if the info it collects is inconsistent.
379+
fn try_add_unstability(
380+
sess: &Session,
381+
attr: &Attribute,
382+
level: &mut Option<(StabilityLevel, Span)>,
383+
) -> Result<(), ErrorGuaranteed> {
384+
if level.is_some() {
385+
return Err(sess
386+
.dcx()
387+
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }));
388+
}
389+
if let Some(new_level) = parse_unstability(sess, attr) {
390+
*level = Some((new_level, attr.span));
391+
}
392+
Ok(())
393+
}
394+
395+
/// Collects stability info from a single `stable`/`rustc_const_stable` attribute, `attr`.
396+
/// Emits an error if the info it collects is inconsistent.
397+
fn try_add_stability(
398+
sess: &Session,
399+
attr: &Attribute,
400+
level: &mut Option<(StabilityLevel, Span)>,
401+
) -> Result<(), ErrorGuaranteed> {
402+
if level.is_some() {
403+
return Err(sess
404+
.dcx()
405+
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }));
406+
}
407+
if let Some(new_level) = parse_stability(sess, attr) {
408+
*level = Some((new_level, attr.span));
409+
}
410+
Ok(())
429411
}
430412

431413
fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> {

0 commit comments

Comments
 (0)