Skip to content

Commit bbcb69a

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 9e13239 commit bbcb69a

File tree

1 file changed

+86
-101
lines changed

1 file changed

+86
-101
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 86 additions & 101 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`
@@ -302,101 +288,69 @@ pub fn find_const_stability(
302288
item_sp: Span,
303289
is_const_fn: bool,
304290
) -> Option<(ConstStability, Span)> {
305-
let mut const_stab: Option<(ConstStability, Span)> = None;
291+
let mut level: Option<(StabilityLevel, Span)> = None;
306292
let mut promotable = false;
307293
let mut const_stable_indirect = None;
308-
let const_stability_level = |level| match level {
309-
StabilityLevel::Unstable { unstables, .. } => ConstStabilityLevel::Unstable { unstables },
310-
StabilityLevel::Stable { since, .. } => ConstStabilityLevel::Stable { since },
311-
};
312294

313295
for attr in attrs {
314296
match attr.name_or_empty() {
315297
sym::rustc_promotable => promotable = true,
316298
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
317299
sym::rustc_const_unstable => {
318-
if const_stab.is_some() {
319-
sess.dcx()
320-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
300+
if try_add_unstability(sess, attr, &mut level).is_err() {
321301
break;
322302
}
323-
324-
if let Some(level) = parse_unstability(sess, attr) {
325-
const_stab = Some((
326-
ConstStability {
327-
level: const_stability_level(level),
328-
const_stable_indirect: false,
329-
promotable: false,
330-
},
331-
attr.span,
332-
));
333-
}
334303
}
335304
sym::rustc_const_stable => {
336-
if const_stab.is_some() {
337-
sess.dcx()
338-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
305+
if try_add_stability(sess, attr, &mut level).is_err() {
339306
break;
340307
}
341-
if let Some(level) = parse_stability(sess, attr) {
342-
const_stab = Some((
343-
ConstStability {
344-
level: const_stability_level(level),
345-
const_stable_indirect: false,
346-
promotable: false,
347-
},
348-
attr.span,
349-
));
350-
}
351308
}
352309
_ => {}
353310
}
354311
}
355312

356313
// Merge promotable and const_stable_indirect into stability info
357-
if promotable {
358-
match &mut const_stab {
359-
Some((stab, _)) => stab.promotable = promotable,
360-
_ => {
361-
_ = sess
362-
.dcx()
363-
.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp })
314+
let (level, stab_sp) = if let Some((level, stab_sp)) = level {
315+
match level {
316+
StabilityLevel::Unstable { unstables, .. } => {
317+
(ConstStabilityLevel::Unstable { unstables }, stab_sp)
364318
}
365-
}
366-
}
367-
if const_stable_indirect.is_some() {
368-
match &mut const_stab {
369-
Some((stab, _)) => {
370-
if stab.is_const_unstable() {
371-
stab.const_stable_indirect = true;
372-
} else {
373-
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
319+
StabilityLevel::Stable { since, .. } => {
320+
if const_stable_indirect.is_some() {
321+
sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
374322
span: item_sp,
375-
})
323+
});
376324
}
325+
(ConstStabilityLevel::Stable { since }, stab_sp)
377326
}
378-
_ => {}
379327
}
380-
}
381-
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
382-
// fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
383-
// stability checks for them. We need to do this because the default for whether an unmarked
384-
// function enforces recursive stability differs between staged-api crates and force-unmarked
385-
// crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
386-
// enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
387-
// assume the function does not have recursive stability. All functions that *do* have recursive
388-
// stability must explicitly record this, and so that's what we do for all `const fn` in a
389-
// staged_api crate.
390-
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
391-
let c = ConstStability {
392-
level: ConstStabilityLevel::Implicit,
393-
const_stable_indirect: const_stable_indirect.is_some(),
394-
promotable: false,
395-
};
396-
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
397-
}
328+
} else {
329+
if promotable {
330+
sess.dcx().emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp });
331+
}
332+
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all
333+
// `const fn` get *some* marker, since we are a staged_api crate and therefore will do
334+
// recursive const stability checks for them. We need to do this because the default for
335+
// whether an unmarked function enforces recursive stability differs between staged-api
336+
// crates and force-unmarked crates: in force-unmarked crates, only functions *explicitly*
337+
// marked `const_stable_indirect` enforce recursive stability. Therefore when
338+
// `lookup_const_stability` is `None`, we have to assume the function does not have
339+
// recursive stability. All functions that *do* have recursive stability must explicitly
340+
// record this, and so that's what we do for all `const fn` in a staged_api crate.
341+
if is_const_fn || const_stable_indirect.is_some() {
342+
(ConstStabilityLevel::Implicit, const_stable_indirect.unwrap_or(DUMMY_SP))
343+
} else {
344+
return None;
345+
}
346+
};
398347

399-
const_stab
348+
let const_stab = ConstStability {
349+
level,
350+
const_stable_indirect: const_stable_indirect.is_some(),
351+
promotable,
352+
};
353+
Some((const_stab, stab_sp))
400354
}
401355

402356
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
@@ -405,23 +359,54 @@ pub fn find_body_stability(
405359
sess: &Session,
406360
attrs: &[Attribute],
407361
) -> Option<(DefaultBodyStability, Span)> {
408-
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
362+
let mut level: Option<(StabilityLevel, Span)> = None;
409363

410364
for attr in attrs {
411365
if attr.has_name(sym::rustc_default_body_unstable) {
412-
if body_stab.is_some() {
413-
sess.dcx()
414-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
366+
if try_add_unstability(sess, attr, &mut level).is_err() {
415367
break;
416368
}
417-
418-
if let Some(level) = parse_unstability(sess, attr) {
419-
body_stab = Some((DefaultBodyStability { level }, attr.span));
420-
}
421369
}
422370
}
423371

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

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

0 commit comments

Comments
 (0)