Skip to content

Commit

Permalink
redo the way we do const feature inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Oct 7, 2024
1 parent 203ca72 commit 720f9e3
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 110 deletions.
91 changes: 62 additions & 29 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::parse::feature_err;
use rustc_session::{RustcVersion, Session};
use rustc_span::Span;
use rustc_span::hygiene::Transparency;
use rustc_span::symbol::{Symbol, kw, sym};
use rustc_span::{DUMMY_SP, Span};

use crate::fluent_generated;
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
Expand Down Expand Up @@ -92,13 +92,15 @@ impl Stability {
#[derive(HashStable_Generic)]
pub struct ConstStability {
pub level: StabilityLevel,
/// This can be `None` for functions that are not even const-unstable, but
/// are tracked here for the purpose of `safe_to_expose_on_stable`.
/// Says whether this function has an explicit `rustc_const_(un)stable` attribute.
/// If `false`, the const stability information was inferred from the regular
/// stability information.
pub has_const_stable_attr: bool,
/// This can be `None` for functions that are not const-callable from outside code under any
/// feature gate, but are tracked here for the purpose of `safe_to_expose_on_stable`.
pub feature: Option<Symbol>,
/// A function that is marked as "safe to expose on stable" must not use any unstable const
/// language features or intrinsics, and all the functions it calls must also be safe to expose
/// on stable. If `level` is `Stable`, this must be `true`.
pub safe_to_expose_on_stable: bool,
/// This is true iff the `const_stable_indirect` attribute is present.
pub const_stable_indirect: bool,
/// whether the function has a `#[rustc_promotable]` attribute
pub promotable: bool,
}
Expand Down Expand Up @@ -274,14 +276,10 @@ pub fn find_stability(

/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
///
/// `inherited_feature_gate` says which feature gate this function should be under if it doesn't
/// declare a gate itself, but has `#[rustc_const_stable_indirect]`.
pub fn find_const_stability(
sess: &Session,
attrs: &[Attribute],
item_sp: Span,
inherited_feature_gate: Option<Symbol>,
) -> Option<(ConstStability, Span)> {
let mut const_stab: Option<(ConstStability, Span)> = None;
let mut promotable = false;
Expand All @@ -302,8 +300,9 @@ pub fn find_const_stability(
const_stab = Some((
ConstStability {
level,
has_const_stable_attr: true,
feature: Some(feature),
safe_to_expose_on_stable: false,
const_stable_indirect: false,
promotable: false,
},
attr.span,
Expand All @@ -320,8 +319,9 @@ pub fn find_const_stability(
const_stab = Some((
ConstStability {
level,
has_const_stable_attr: true,
feature: Some(feature),
safe_to_expose_on_stable: true,
const_stable_indirect: false,
promotable: false,
},
attr.span,
Expand All @@ -347,36 +347,69 @@ pub fn find_const_stability(
match &mut const_stab {
Some((stab, _)) => {
if stab.is_const_unstable() {
stab.safe_to_expose_on_stable = true;
stab.const_stable_indirect = true;
} else {
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
span: item_sp,
})
}
}
_ => {
// `#[rustc_const_stable_indirect]` implicitly makes the function unstably const,
// inheriting the feature gate from `#[unstable]` if it xists, or without any
// feature gate otherwise.
let c = ConstStability {
feature: inherited_feature_gate,
safe_to_expose_on_stable: true,
promotable: false,
level: StabilityLevel::Unstable {
reason: UnstableReason::Default,
issue: None,
is_soft: false,
implied_by: None,
},
};
const_stab = Some((c, DUMMY_SP));
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
// the `default_const_unstable` logic.
}
}
}

const_stab
}

/// Called for `fn` that don't have a const stability.
///
/// `effective_reg_stability` must be the effecive regular stability, i.e. after applying all the
/// rules about "inherited" stability.
pub fn default_const_stability(
_sess: &Session,
is_const_fn: bool,
attrs: &[Attribute],
effective_reg_stability: Option<&Stability>,
) -> Option<ConstStability> {
let const_stable_indirect =
attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
// Intrinsics are *not* `const fn` here, and yet we want to add a default const stability
// for them if they are marked `const_stable_indirect`.
if (is_const_fn || const_stable_indirect)
&& let Some(reg_stability) = effective_reg_stability
&& reg_stability.level.is_unstable()
{
// This has a feature gate, reuse that for const stability.
// We only want to do this if it is an unstable feature gate.
Some(ConstStability {
feature: Some(reg_stability.feature),
has_const_stable_attr: false,
const_stable_indirect,
promotable: false,
level: reg_stability.level,
})
} else if const_stable_indirect {
// Make it const-unstable without a feature gate, to record the `const_stable_indirect`.
Some(ConstStability {
feature: None,
has_const_stable_attr: false,
const_stable_indirect,
promotable: false,
level: StabilityLevel::Unstable {
reason: UnstableReason::Default,
issue: None,
is_soft: false,
implied_by: None,
},
})
} else {
None
}
}

/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
/// Returns `None` if no stability attributes are found.
pub fn find_body_stability(
Expand Down
13 changes: 7 additions & 6 deletions compiler/rustc_const_eval/src/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,16 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b
// We allow calling unmarked local functions *in the current crate*. For the cross-crate
// case we require the other crate to explicitly add `#[rustc_const_stable_indirect]` as
// a promise that this function is meant to be indirectly const-stable, which will make
// `lookup_const_stability` return `Some`.
// `lookup_const_stability` return `Some`. This ensures that the other crate checked
// recursive const vailidty on that function, even if the other crate is not using
// `staged_api`.
def_id.is_local()
}
Some(stab) => {
// `safe_to_expose_on_stable` implies `is_const_stable`.
if stab.is_const_stable() {
assert!(stab.safe_to_expose_on_stable);
}
stab.safe_to_expose_on_stable
stab.is_const_stable() || stab.const_stable_indirect ||
// Non-intrinsic `const fn` without an explicit const stability attribute (i.e.,
// with only the implied attribute) are safe to expose on stable.
(!stab.has_const_stable_attr && tcx.intrinsic(def_id).is_none())
}
}
}
6 changes: 1 addition & 5 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,11 +865,7 @@ impl SyntaxExtension {
})
.unwrap_or_else(|| (None, helper_attrs));
let stability = attr::find_stability(sess, attrs, span);
// FIXME: this will give a different result than the normal stability computation, since we
// don't inherit stability from the parent. But that's true even for `stability` above so
// it's probably okay?
let const_stability =
attr::find_const_stability(sess, attrs, span, stability.map(|(s, _)| s.feature));
let const_stability = attr::find_const_stability(sess, attrs, span);
let body_stability = attr::find_body_stability(sess, attrs);
if let Some((_, sp)) = const_stability {
sess.dcx().emit_err(errors::MacroConstStability {
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ passes_maybe_string_interpolation = you might have meant to use string interpola
passes_missing_const_err =
attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
.help = make the function or method const
.label = attribute specified here
passes_missing_const_stab_attr =
{$descr} has missing const stability attribute
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1551,8 +1551,6 @@ pub(crate) struct MissingConstErr {
#[primary_span]
#[help]
pub fn_sig_span: Span,
#[label]
pub const_span: Span,
}

#[derive(Diagnostic)]
Expand Down
Loading

0 comments on commit 720f9e3

Please sign in to comment.