Skip to content
58 changes: 57 additions & 1 deletion compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ pub struct CfgHideShow {
pub values: ThinVec<CfgInfo>,
}

#[derive(Clone, Debug, Default, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
#[derive(Clone, Debug, Default, HashStable_Generic, Decodable, PrintAttribute)]
pub struct DocAttribute {
pub aliases: FxIndexMap<Symbol, Span>,
pub hidden: Option<Span>,
Expand Down Expand Up @@ -566,6 +566,62 @@ pub struct DocAttribute {
pub no_crate_inject: Option<Span>,
}

impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute {
fn encode(&self, encoder: &mut E) {
let DocAttribute {
aliases,
hidden,
inline,
cfg,
auto_cfg,
auto_cfg_change,
fake_variadic,
keyword,
attribute,
masked,
notable_trait,
search_unbox,
html_favicon_url,
html_logo_url,
html_playground_url,
html_root_url,
html_no_source,
issue_tracker_base_url,
rust_logo,
test_attrs,
no_crate_inject,
} = self;
rustc_serialize::Encodable::<E>::encode(aliases, encoder);
rustc_serialize::Encodable::<E>::encode(hidden, encoder);

// FIXME: The `doc(inline)` attribute is never encoded, but is it actually the right thing
// to do? I suspect the condition was broken, should maybe instead not encode anything if we
// have `doc(no_inline)`.
let inline: ThinVec<_> =
inline.iter().filter(|(i, _)| *i != DocInline::Inline).cloned().collect();
rustc_serialize::Encodable::<E>::encode(&inline, encoder);

rustc_serialize::Encodable::<E>::encode(cfg, encoder);
rustc_serialize::Encodable::<E>::encode(auto_cfg, encoder);
rustc_serialize::Encodable::<E>::encode(auto_cfg_change, encoder);
rustc_serialize::Encodable::<E>::encode(fake_variadic, encoder);
rustc_serialize::Encodable::<E>::encode(keyword, encoder);
rustc_serialize::Encodable::<E>::encode(attribute, encoder);
rustc_serialize::Encodable::<E>::encode(masked, encoder);
rustc_serialize::Encodable::<E>::encode(notable_trait, encoder);
rustc_serialize::Encodable::<E>::encode(search_unbox, encoder);
rustc_serialize::Encodable::<E>::encode(html_favicon_url, encoder);
rustc_serialize::Encodable::<E>::encode(html_logo_url, encoder);
rustc_serialize::Encodable::<E>::encode(html_playground_url, encoder);
rustc_serialize::Encodable::<E>::encode(html_root_url, encoder);
rustc_serialize::Encodable::<E>::encode(html_no_source, encoder);
rustc_serialize::Encodable::<E>::encode(issue_tracker_base_url, encoder);
rustc_serialize::Encodable::<E>::encode(rust_logo, encoder);
rustc_serialize::Encodable::<E>::encode(test_attrs, encoder);
rustc_serialize::Encodable::<E>::encode(no_crate_inject, encoder);
}
}

/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -879,13 +879,9 @@ fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool
should_encode = true;
}
} else if let hir::Attribute::Parsed(AttributeKind::Doc(d)) = attr {
// If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in
// `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates.
if d.inline.is_empty() {
should_encode = true;
if d.hidden.is_some() {
state.is_doc_hidden = true;
}
should_encode = true;
if d.hidden.is_some() {
state.is_doc_hidden = true;
}
} else if let &[sym::diagnostic, seg] = &*attr.path() {
should_encode = rustc_feature::is_stable_diagnostic_attribute(seg, state.features);
Expand Down
35 changes: 17 additions & 18 deletions compiler/rustc_mir_build/src/builder/matches/buckets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use tracing::debug;

use crate::builder::Builder;
use crate::builder::matches::test::is_switch_ty;
use crate::builder::matches::{Candidate, Test, TestBranch, TestCase, TestKind};
use crate::builder::matches::{Candidate, Test, TestBranch, TestKind, TestableCase};

/// Output of [`Builder::partition_candidates_into_buckets`].
pub(crate) struct PartitionedCandidates<'tcx, 'b, 'c> {
Expand Down Expand Up @@ -140,12 +140,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// branch, so it can be removed. If false, the match pair is _compatible_
// with its test branch, but still needs a more specific test.
let fully_matched;
let ret = match (&test.kind, &match_pair.test_case) {
let ret = match (&test.kind, &match_pair.testable_case) {
// If we are performing a variant switch, then this
// informs variant patterns, but nothing else.
(
&TestKind::Switch { adt_def: tested_adt_def },
&TestCase::Variant { adt_def, variant_index },
&TestableCase::Variant { adt_def, variant_index },
) => {
assert_eq!(adt_def, tested_adt_def);
fully_matched = true;
Expand All @@ -159,24 +159,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// things out here, in some cases.
//
// FIXME(Zalathar): Is the `is_switch_ty` test unnecessary?
(TestKind::SwitchInt, &TestCase::Constant { value })
(TestKind::SwitchInt, &TestableCase::Constant { value })
if is_switch_ty(match_pair.pattern_ty) =>
{
// An important invariant of candidate bucketing is that a candidate
// must not match in multiple branches. For `SwitchInt` tests, adding
// a new value might invalidate that property for range patterns that
// have already been partitioned into the failure arm, so we must take care
// not to add such values here.
let is_covering_range = |test_case: &TestCase<'tcx>| {
test_case.as_range().is_some_and(|range| {
let is_covering_range = |testable_case: &TestableCase<'tcx>| {
testable_case.as_range().is_some_and(|range| {
matches!(range.contains(value, self.tcx), None | Some(true))
})
};
let is_conflicting_candidate = |candidate: &&mut Candidate<'tcx>| {
candidate
.match_pairs
.iter()
.any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case))
candidate.match_pairs.iter().any(|mp| {
mp.place == Some(test_place) && is_covering_range(&mp.testable_case)
})
};
if prior_candidates
.get(&TestBranch::Failure)
Expand All @@ -189,7 +188,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Some(TestBranch::Constant(value))
}
}
(TestKind::SwitchInt, TestCase::Range(range)) => {
(TestKind::SwitchInt, TestableCase::Range(range)) => {
// When performing a `SwitchInt` test, a range pattern can be
// sorted into the failure arm if it doesn't contain _any_ of
// the values being tested. (This restricts what values can be
Expand All @@ -207,7 +206,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
})
}

(TestKind::If, TestCase::Constant { value }) => {
(TestKind::If, TestableCase::Constant { value }) => {
fully_matched = true;
let value = value.try_to_bool().unwrap_or_else(|| {
span_bug!(test.span, "expected boolean value but got {value:?}")
Expand All @@ -217,7 +216,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

(
&TestKind::Len { len: test_len, op: BinOp::Eq },
&TestCase::Slice { len, variable_length },
&TestableCase::Slice { len, variable_length },
) => {
match (test_len.cmp(&(len as u64)), variable_length) {
(Ordering::Equal, false) => {
Expand Down Expand Up @@ -249,7 +248,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
(
&TestKind::Len { len: test_len, op: BinOp::Ge },
&TestCase::Slice { len, variable_length },
&TestableCase::Slice { len, variable_length },
) => {
// the test is `$actual_len >= test_len`
match (test_len.cmp(&(len as u64)), variable_length) {
Expand Down Expand Up @@ -281,7 +280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

(TestKind::Range(test), TestCase::Range(pat)) => {
(TestKind::Range(test), TestableCase::Range(pat)) => {
if test == pat {
fully_matched = true;
Some(TestBranch::Success)
Expand All @@ -292,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None }
}
}
(TestKind::Range(range), &TestCase::Constant { value }) => {
(TestKind::Range(range), &TestableCase::Constant { value }) => {
fully_matched = false;
if !range.contains(value, self.tcx)? {
// `value` is not contained in the testing range,
Expand All @@ -303,7 +302,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => {
(TestKind::Eq { value: test_val, .. }, TestableCase::Constant { value: case_val }) => {
if test_val == case_val {
fully_matched = true;
Some(TestBranch::Success)
Expand All @@ -313,7 +312,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

(TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
(TestKind::Deref { temp: test_temp, .. }, TestableCase::Deref { temp, .. })
if test_temp == temp =>
{
fully_matched = true;
Expand Down
26 changes: 15 additions & 11 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt};

use crate::builder::Builder;
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestableCase};

impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
Expand Down Expand Up @@ -132,7 +132,7 @@ impl<'tcx> MatchPairTree<'tcx> {

let place = place_builder.try_to_place(cx);
let mut subpairs = Vec::new();
let test_case = match pattern.kind {
let testable_case = match pattern.kind {
PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,

PatKind::Or { ref pats } => {
Expand All @@ -146,18 +146,18 @@ impl<'tcx> MatchPairTree<'tcx> {
// FIXME(@dianne): this needs updating/removing if we always merge or-patterns
extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
}
Some(TestCase::Or { pats })
Some(TestableCase::Or { pats })
}

PatKind::Range(ref range) => {
if range.is_full_range(cx.tcx) == Some(true) {
None
} else {
Some(TestCase::Range(Arc::clone(range)))
Some(TestableCase::Range(Arc::clone(range)))
}
}

PatKind::Constant { value } => Some(TestCase::Constant { value }),
PatKind::Constant { value } => Some(TestableCase::Constant { value }),

PatKind::AscribeUserType {
ascription: Ascription { ref annotation, variance },
Expand Down Expand Up @@ -256,7 +256,7 @@ impl<'tcx> MatchPairTree<'tcx> {
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
None
} else {
Some(TestCase::Slice {
Some(TestableCase::Slice {
len: prefix.len() + suffix.len(),
variable_length: slice.is_some(),
})
Expand All @@ -275,7 +275,11 @@ impl<'tcx> MatchPairTree<'tcx> {
cx.def_id.into(),
)
}) && !adt_def.variant_list_has_applicable_non_exhaustive();
if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
if irrefutable {
None
} else {
Some(TestableCase::Variant { adt_def, variant_index })
}
}

PatKind::Leaf { ref subpatterns } => {
Expand Down Expand Up @@ -331,17 +335,17 @@ impl<'tcx> MatchPairTree<'tcx> {
&mut subpairs,
extra_data,
);
Some(TestCase::Deref { temp, mutability })
Some(TestableCase::Deref { temp, mutability })
}

PatKind::Never => Some(TestCase::Never),
PatKind::Never => Some(TestableCase::Never),
};

if let Some(test_case) = test_case {
if let Some(testable_case) = testable_case {
// This pattern is refutable, so push a new match-pair node.
match_pairs.push(MatchPairTree {
place,
test_case,
testable_case,
subpairs,
pattern_ty: pattern.ty,
pattern_span: pattern.span,
Expand Down
25 changes: 14 additions & 11 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ struct Candidate<'tcx> {
/// (see [`Builder::test_remaining_match_pairs_after_or`]).
///
/// Invariants:
/// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
/// - All or-patterns ([`TestableCase::Or`]) have been sorted to the end.
match_pairs: Vec<MatchPairTree<'tcx>>,

/// ...and if this is non-empty, one of these subcandidates also has to match...
Expand Down Expand Up @@ -1164,12 +1164,15 @@ impl<'tcx> Candidate<'tcx> {

/// Restores the invariant that or-patterns must be sorted to the end.
fn sort_match_pairs(&mut self) {
self.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
self.match_pairs.sort_by_key(|pair| matches!(pair.testable_case, TestableCase::Or { .. }));
}

/// Returns whether the first match pair of this candidate is an or-pattern.
fn starts_with_or_pattern(&self) -> bool {
matches!(&*self.match_pairs, [MatchPairTree { test_case: TestCase::Or { .. }, .. }, ..])
matches!(
&*self.match_pairs,
[MatchPairTree { testable_case: TestableCase::Or { .. }, .. }, ..]
)
}

/// Visit the leaf candidates (those with no subcandidates) contained in
Expand Down Expand Up @@ -1261,7 +1264,7 @@ struct Ascription<'tcx> {
/// Instead they participate in or-pattern expansion, where they are transformed into
/// subcandidates. See [`Builder::expand_and_match_or_candidates`].
#[derive(Debug, Clone)]
enum TestCase<'tcx> {
enum TestableCase<'tcx> {
Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
Constant { value: ty::Value<'tcx> },
Range(Arc<PatRange<'tcx>>),
Expand All @@ -1271,7 +1274,7 @@ enum TestCase<'tcx> {
Or { pats: Box<[FlatPat<'tcx>]> },
}

impl<'tcx> TestCase<'tcx> {
impl<'tcx> TestableCase<'tcx> {
fn as_range(&self) -> Option<&PatRange<'tcx>> {
if let Self::Range(v) = self { Some(v.as_ref()) } else { None }
}
Expand All @@ -1289,12 +1292,12 @@ pub(crate) struct MatchPairTree<'tcx> {
/// ---
/// This can be `None` if it referred to a non-captured place in a closure.
///
/// Invariant: Can only be `None` when `test_case` is `Or`.
/// Invariant: Can only be `None` when `testable_case` is `Or`.
/// Therefore this must be `Some(_)` after or-pattern expansion.
place: Option<Place<'tcx>>,

/// ... must pass this test...
test_case: TestCase<'tcx>,
testable_case: TestableCase<'tcx>,

/// ... and these subpairs must match.
///
Expand All @@ -1317,7 +1320,7 @@ enum TestKind<'tcx> {
/// Test what enum variant a value is.
///
/// The subset of expected variants is not stored here; instead they are
/// extracted from the [`TestCase`]s of the candidates participating in the
/// extracted from the [`TestableCase`]s of the candidates participating in the
/// test.
Switch {
/// The enum type being tested.
Expand All @@ -1327,7 +1330,7 @@ enum TestKind<'tcx> {
/// Test what value an integer or `char` has.
///
/// The test's target values are not stored here; instead they are extracted
/// from the [`TestCase`]s of the candidates participating in the test.
/// from the [`TestableCase`]s of the candidates participating in the test.
SwitchInt,

/// Test whether a `bool` is `true` or `false`.
Expand Down Expand Up @@ -1948,7 +1951,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate: &mut Candidate<'tcx>,
match_pair: MatchPairTree<'tcx>,
) {
let TestCase::Or { pats } = match_pair.test_case else { bug!() };
let TestableCase::Or { pats } = match_pair.testable_case else { bug!() };
debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
candidate.or_span = Some(match_pair.pattern_span);
candidate.subcandidates = pats
Expand Down Expand Up @@ -2116,7 +2119,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug_assert!(
remaining_match_pairs
.iter()
.all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
.all(|match_pair| matches!(match_pair.testable_case, TestableCase::Or { .. }))
);

// Visit each leaf candidate within this subtree, add a copy of the remaining
Expand Down
Loading
Loading