Skip to content

Commit 9573d7b

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 a78f8e7 commit 9573d7b

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
@@ -256,54 +256,40 @@ pub fn find_stability(
256256
attrs: &[Attribute],
257257
item_sp: Span,
258258
) -> Option<(Stability, Span)> {
259-
let mut stab: Option<(Stability, Span)> = None;
259+
let mut level: Option<(StabilityLevel, Span)> = None;
260260
let mut allowed_through_unstable_modules = false;
261261

262262
for attr in attrs {
263263
match attr.name_or_empty() {
264264
sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
265265
sym::unstable => {
266-
if stab.is_some() {
267-
sess.dcx()
268-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
266+
if try_add_unstability(sess, attr, &mut level).is_err() {
269267
break;
270268
}
271-
272-
if let Some(level) = parse_unstability(sess, attr) {
273-
stab = Some((Stability { level }, attr.span));
274-
}
275269
}
276270
sym::stable => {
277-
if stab.is_some() {
278-
sess.dcx()
279-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
271+
if try_add_stability(sess, attr, &mut level).is_err() {
280272
break;
281273
}
282-
if let Some(level) = parse_stability(sess, attr) {
283-
stab = Some((Stability { level }, attr.span));
284-
}
285274
}
286275
_ => {}
287276
}
288277
}
289278

290279
if allowed_through_unstable_modules {
291-
match &mut stab {
292-
Some((
293-
Stability {
294-
level: StabilityLevel::Stable { allowed_through_unstable_modules, .. },
295-
..
296-
},
297-
_,
298-
)) => *allowed_through_unstable_modules = true,
280+
match &mut level {
281+
Some((StabilityLevel::Stable { allowed_through_unstable_modules, .. }, _)) => {
282+
*allowed_through_unstable_modules = true
283+
}
299284
_ => {
300285
sess.dcx()
301286
.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
302287
}
303288
}
304289
}
305290

306-
stab
291+
let (level, stab_sp) = level?;
292+
Some((Stability { level }, stab_sp))
307293
}
308294

309295
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
@@ -316,101 +302,69 @@ pub fn find_const_stability(
316302
item_sp: Span,
317303
is_const_fn: bool,
318304
) -> Option<(ConstStability, Span)> {
319-
let mut const_stab: Option<(ConstStability, Span)> = None;
305+
let mut level: Option<(StabilityLevel, Span)> = None;
320306
let mut promotable = false;
321307
let mut const_stable_indirect = None;
322-
let const_stability_level = |level| match level {
323-
StabilityLevel::Unstable { unstables, .. } => ConstStabilityLevel::Unstable { unstables },
324-
StabilityLevel::Stable { since, .. } => ConstStabilityLevel::Stable { since },
325-
};
326308

327309
for attr in attrs {
328310
match attr.name_or_empty() {
329311
sym::rustc_promotable => promotable = true,
330312
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
331313
sym::rustc_const_unstable => {
332-
if const_stab.is_some() {
333-
sess.dcx()
334-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
314+
if try_add_unstability(sess, attr, &mut level).is_err() {
335315
break;
336316
}
337-
338-
if let Some(level) = parse_unstability(sess, attr) {
339-
const_stab = Some((
340-
ConstStability {
341-
level: const_stability_level(level),
342-
const_stable_indirect: false,
343-
promotable: false,
344-
},
345-
attr.span,
346-
));
347-
}
348317
}
349318
sym::rustc_const_stable => {
350-
if const_stab.is_some() {
351-
sess.dcx()
352-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
319+
if try_add_stability(sess, attr, &mut level).is_err() {
353320
break;
354321
}
355-
if let Some(level) = parse_stability(sess, attr) {
356-
const_stab = Some((
357-
ConstStability {
358-
level: const_stability_level(level),
359-
const_stable_indirect: false,
360-
promotable: false,
361-
},
362-
attr.span,
363-
));
364-
}
365322
}
366323
_ => {}
367324
}
368325
}
369326

370327
// Merge promotable and const_stable_indirect into stability info
371-
if promotable {
372-
match &mut const_stab {
373-
Some((stab, _)) => stab.promotable = promotable,
374-
_ => {
375-
_ = sess
376-
.dcx()
377-
.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp })
328+
let (level, stab_sp) = if let Some((level, stab_sp)) = level {
329+
match level {
330+
StabilityLevel::Unstable { unstables, .. } => {
331+
(ConstStabilityLevel::Unstable { unstables }, stab_sp)
378332
}
379-
}
380-
}
381-
if const_stable_indirect.is_some() {
382-
match &mut const_stab {
383-
Some((stab, _)) => {
384-
if stab.is_const_unstable() {
385-
stab.const_stable_indirect = true;
386-
} else {
387-
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
333+
StabilityLevel::Stable { since, .. } => {
334+
if const_stable_indirect.is_some() {
335+
sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
388336
span: item_sp,
389-
})
337+
});
390338
}
339+
(ConstStabilityLevel::Stable { since }, stab_sp)
391340
}
392-
_ => {}
393341
}
394-
}
395-
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
396-
// fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
397-
// stability checks for them. We need to do this because the default for whether an unmarked
398-
// function enforces recursive stability differs between staged-api crates and force-unmarked
399-
// crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
400-
// enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
401-
// assume the function does not have recursive stability. All functions that *do* have recursive
402-
// stability must explicitly record this, and so that's what we do for all `const fn` in a
403-
// staged_api crate.
404-
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
405-
let c = ConstStability {
406-
level: ConstStabilityLevel::ImplicitUnstable,
407-
const_stable_indirect: const_stable_indirect.is_some(),
408-
promotable: false,
409-
};
410-
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
411-
}
342+
} else {
343+
if promotable {
344+
sess.dcx().emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp });
345+
}
346+
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all
347+
// `const fn` get *some* marker, since we are a staged_api crate and therefore will do
348+
// recursive const stability checks for them. We need to do this because the default for
349+
// whether an unmarked function enforces recursive stability differs between staged-api
350+
// crates and force-unmarked crates: in force-unmarked crates, only functions *explicitly*
351+
// marked `const_stable_indirect` enforce recursive stability. Therefore when
352+
// `lookup_const_stability` is `None`, we have to assume the function does not have
353+
// recursive stability. All functions that *do* have recursive stability must explicitly
354+
// record this, and so that's what we do for all `const fn` in a staged_api crate.
355+
if is_const_fn || const_stable_indirect.is_some() {
356+
(ConstStabilityLevel::ImplicitUnstable, const_stable_indirect.unwrap_or(DUMMY_SP))
357+
} else {
358+
return None;
359+
}
360+
};
412361

413-
const_stab
362+
let const_stab = ConstStability {
363+
level,
364+
const_stable_indirect: const_stable_indirect.is_some(),
365+
promotable,
366+
};
367+
Some((const_stab, stab_sp))
414368
}
415369

416370
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
@@ -419,23 +373,54 @@ pub fn find_body_stability(
419373
sess: &Session,
420374
attrs: &[Attribute],
421375
) -> Option<(DefaultBodyStability, Span)> {
422-
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
376+
let mut level: Option<(StabilityLevel, Span)> = None;
423377

424378
for attr in attrs {
425379
if attr.has_name(sym::rustc_default_body_unstable) {
426-
if body_stab.is_some() {
427-
sess.dcx()
428-
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
380+
if try_add_unstability(sess, attr, &mut level).is_err() {
429381
break;
430382
}
431-
432-
if let Some(level) = parse_unstability(sess, attr) {
433-
body_stab = Some((DefaultBodyStability { level }, attr.span));
434-
}
435383
}
436384
}
437385

438-
body_stab
386+
let (level, stab_sp) = level?;
387+
Some((DefaultBodyStability { level }, stab_sp))
388+
}
389+
390+
/// Collects stability info from one `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
391+
/// attribute, `attr`. Emits an error if the info it collects is inconsistent.
392+
fn try_add_unstability(
393+
sess: &Session,
394+
attr: &Attribute,
395+
level: &mut Option<(StabilityLevel, Span)>,
396+
) -> Result<(), ErrorGuaranteed> {
397+
if level.is_some() {
398+
return Err(sess
399+
.dcx()
400+
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }));
401+
}
402+
if let Some(new_level) = parse_unstability(sess, attr) {
403+
*level = Some((new_level, attr.span));
404+
}
405+
Ok(())
406+
}
407+
408+
/// Collects stability info from a single `stable`/`rustc_const_stable` attribute, `attr`.
409+
/// Emits an error if the info it collects is inconsistent.
410+
fn try_add_stability(
411+
sess: &Session,
412+
attr: &Attribute,
413+
level: &mut Option<(StabilityLevel, Span)>,
414+
) -> Result<(), ErrorGuaranteed> {
415+
if level.is_some() {
416+
return Err(sess
417+
.dcx()
418+
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }));
419+
}
420+
if let Some(new_level) = parse_stability(sess, attr) {
421+
*level = Some((new_level, attr.span));
422+
}
423+
Ok(())
439424
}
440425

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

0 commit comments

Comments
 (0)