Skip to content

Commit 26e29af

Browse files
committed
Auto merge of #149063 - matthiaskrgr:rollup-6z23izv, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #147887 (Improve the documentation of atomic::fence) - #148281 (repr(transparent) check: do not compute check_unsuited more than once) - #148484 (Fix suggestion for the `cfg!` macro) - #149057 (`rust-analyzer` subtree update) - #149061 (debug-assert FixedSizeEncoding invariant) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 3d461af + ceb33e9 commit 26e29af

File tree

82 files changed

+6193
-513
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+6193
-513
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_ast::token::Delimiter;
22
use rustc_ast::tokenstream::DelimSpan;
33
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token};
44
use rustc_errors::{Applicability, PResult};
5-
use rustc_feature::{AttributeTemplate, Features, template};
5+
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template};
66
use rustc_hir::attrs::CfgEntry;
77
use rustc_hir::{AttrPath, RustcVersion};
88
use rustc_parse::parser::{ForceCollect, Parser};
@@ -323,8 +323,8 @@ pub fn parse_cfg_attr(
323323
}) {
324324
Ok(r) => return Some(r),
325325
Err(e) => {
326-
let suggestions =
327-
CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr);
326+
let suggestions = CFG_ATTR_TEMPLATE
327+
.suggestions(AttrSuggestionStyle::Attribute(cfg_attr.style), sym::cfg_attr);
328328
e.with_span_suggestions(
329329
cfg_attr.span,
330330
"must be of the form",
@@ -355,7 +355,8 @@ pub fn parse_cfg_attr(
355355
path: AttrPath::from_ast(&cfg_attr.get_normal_item().path),
356356
description: ParsedDescription::Attribute,
357357
reason,
358-
suggestions: CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr),
358+
suggestions: CFG_ATTR_TEMPLATE
359+
.suggestions(AttrSuggestionStyle::Attribute(cfg_attr.style), sym::cfg_attr),
359360
});
360361
}
361362
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::sync::LazyLock;
66
use private::Sealed;
77
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
88
use rustc_errors::{Diag, Diagnostic, Level};
9-
use rustc_feature::AttributeTemplate;
9+
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
1010
use rustc_hir::attrs::AttributeKind;
1111
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
1212
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
@@ -637,9 +637,15 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
637637
}
638638

639639
pub(crate) fn suggestions(&self) -> Vec<String> {
640-
// If the outer and inner spans are equal, we are parsing an attribute from `cfg_attr`,
641-
// So don't display an attribute style in the suggestions
642-
let style = (self.attr_span != self.inner_span).then_some(self.attr_style);
640+
let style = match self.parsed_description {
641+
// If the outer and inner spans are equal, we are parsing an embedded attribute
642+
ParsedDescription::Attribute if self.attr_span == self.inner_span => {
643+
AttrSuggestionStyle::EmbeddedAttribute
644+
}
645+
ParsedDescription::Attribute => AttrSuggestionStyle::Attribute(self.attr_style),
646+
ParsedDescription::Macro => AttrSuggestionStyle::Macro,
647+
};
648+
643649
self.template.suggestions(style, &self.attr_path)
644650
}
645651
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,28 +132,45 @@ pub struct AttributeTemplate {
132132
pub docs: Option<&'static str>,
133133
}
134134

135+
pub enum AttrSuggestionStyle {
136+
/// The suggestion is styled for a normal attribute.
137+
/// The `AttrStyle` determines whether this is an inner or outer attribute.
138+
Attribute(AttrStyle),
139+
/// The suggestion is styled for an attribute embedded into another attribute.
140+
/// For example, attributes inside `#[cfg_attr(true, attr(...)]`.
141+
EmbeddedAttribute,
142+
/// The suggestion is styled for macros that are parsed with attribute parsers.
143+
/// For example, the `cfg!(predicate)` macro.
144+
Macro,
145+
}
146+
135147
impl AttributeTemplate {
136148
pub fn suggestions(
137149
&self,
138-
style: Option<AttrStyle>,
150+
style: AttrSuggestionStyle,
139151
name: impl std::fmt::Display,
140152
) -> Vec<String> {
141-
let mut suggestions = vec![];
142-
let (start, end) = match style {
143-
Some(AttrStyle::Outer) => ("#[", "]"),
144-
Some(AttrStyle::Inner) => ("#![", "]"),
145-
None => ("", ""),
153+
let (start, macro_call, end) = match style {
154+
AttrSuggestionStyle::Attribute(AttrStyle::Outer) => ("#[", "", "]"),
155+
AttrSuggestionStyle::Attribute(AttrStyle::Inner) => ("#![", "", "]"),
156+
AttrSuggestionStyle::Macro => ("", "!", ""),
157+
AttrSuggestionStyle::EmbeddedAttribute => ("", "", ""),
146158
};
159+
160+
let mut suggestions = vec![];
161+
147162
if self.word {
163+
debug_assert!(macro_call.is_empty(), "Macro suggestions use list style");
148164
suggestions.push(format!("{start}{name}{end}"));
149165
}
150166
if let Some(descr) = self.list {
151167
for descr in descr {
152-
suggestions.push(format!("{start}{name}({descr}){end}"));
168+
suggestions.push(format!("{start}{name}{macro_call}({descr}){end}"));
153169
}
154170
}
155171
suggestions.extend(self.one_of.iter().map(|&word| format!("{start}{name}({word}){end}")));
156172
if let Some(descr) = self.name_value_str {
173+
debug_assert!(macro_call.is_empty(), "Macro suggestions use list style");
157174
for descr in descr {
158175
suggestions.push(format!("{start}{name} = \"{descr}\"{end}"));
159176
}

compiler/rustc_feature/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,10 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
129129

130130
pub use accepted::ACCEPTED_LANG_FEATURES;
131131
pub use builtin_attrs::{
132-
AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
133-
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate,
134-
find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr,
132+
AttrSuggestionStyle, AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate,
133+
AttributeType, BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg,
134+
encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
135+
is_valid_for_get_attr,
135136
};
136137
pub use removed::REMOVED_LANG_FEATURES;
137138
pub use unstable::{

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 56 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,22 +1542,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15421542

15431543
let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did());
15441544
// For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST).
1545-
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1546-
// fields or `repr(C)`. We call those fields "unsuited".
15471545
struct FieldInfo<'tcx> {
15481546
span: Span,
15491547
trivial: bool,
1550-
unsuited: Option<UnsuitedInfo<'tcx>>,
1551-
}
1552-
struct UnsuitedInfo<'tcx> {
1553-
/// The source of the problem, a type that is found somewhere within the field type.
15541548
ty: Ty<'tcx>,
1555-
reason: UnsuitedReason,
1556-
}
1557-
enum UnsuitedReason {
1558-
NonExhaustive,
1559-
PrivateField,
1560-
ReprC,
15611549
}
15621550

15631551
let field_infos = adt.all_fields().map(|field| {
@@ -1566,60 +1554,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15661554
// We are currently checking the type this field came from, so it must be local
15671555
let span = tcx.hir_span_if_local(field.did).unwrap();
15681556
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
1569-
if !trivial {
1570-
// No need to even compute `unsuited`.
1571-
return FieldInfo { span, trivial, unsuited: None };
1572-
}
1573-
1574-
fn check_unsuited<'tcx>(
1575-
tcx: TyCtxt<'tcx>,
1576-
typing_env: ty::TypingEnv<'tcx>,
1577-
ty: Ty<'tcx>,
1578-
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1579-
// We can encounter projections during traversal, so ensure the type is normalized.
1580-
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
1581-
match ty.kind() {
1582-
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),
1583-
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
1584-
ty::Adt(def, args) => {
1585-
if !def.did().is_local()
1586-
&& !find_attr!(
1587-
tcx.get_all_attrs(def.did()),
1588-
AttributeKind::PubTransparent(_)
1589-
)
1590-
{
1591-
let non_exhaustive = def.is_variant_list_non_exhaustive()
1592-
|| def
1593-
.variants()
1594-
.iter()
1595-
.any(ty::VariantDef::is_field_list_non_exhaustive);
1596-
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1597-
if non_exhaustive || has_priv {
1598-
return ControlFlow::Break(UnsuitedInfo {
1599-
ty,
1600-
reason: if non_exhaustive {
1601-
UnsuitedReason::NonExhaustive
1602-
} else {
1603-
UnsuitedReason::PrivateField
1604-
},
1605-
});
1606-
}
1607-
}
1608-
if def.repr().c() {
1609-
return ControlFlow::Break(UnsuitedInfo {
1610-
ty,
1611-
reason: UnsuitedReason::ReprC,
1612-
});
1613-
}
1614-
def.all_fields()
1615-
.map(|field| field.ty(tcx, args))
1616-
.try_for_each(|t| check_unsuited(tcx, typing_env, t))
1617-
}
1618-
_ => ControlFlow::Continue(()),
1619-
}
1620-
}
1621-
1622-
FieldInfo { span, trivial, unsuited: check_unsuited(tcx, typing_env, ty).break_value() }
1557+
FieldInfo { span, trivial, ty }
16231558
});
16241559

16251560
let non_trivial_fields = field_infos
@@ -1637,10 +1572,63 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
16371572
return;
16381573
}
16391574

1575+
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private
1576+
// fields or `repr(C)`. We call those fields "unsuited".
1577+
struct UnsuitedInfo<'tcx> {
1578+
/// The source of the problem, a type that is found somewhere within the field type.
1579+
ty: Ty<'tcx>,
1580+
reason: UnsuitedReason,
1581+
}
1582+
enum UnsuitedReason {
1583+
NonExhaustive,
1584+
PrivateField,
1585+
ReprC,
1586+
}
1587+
1588+
fn check_unsuited<'tcx>(
1589+
tcx: TyCtxt<'tcx>,
1590+
typing_env: ty::TypingEnv<'tcx>,
1591+
ty: Ty<'tcx>,
1592+
) -> ControlFlow<UnsuitedInfo<'tcx>> {
1593+
// We can encounter projections during traversal, so ensure the type is normalized.
1594+
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
1595+
match ty.kind() {
1596+
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),
1597+
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
1598+
ty::Adt(def, args) => {
1599+
if !def.did().is_local()
1600+
&& !find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_))
1601+
{
1602+
let non_exhaustive = def.is_variant_list_non_exhaustive()
1603+
|| def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);
1604+
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
1605+
if non_exhaustive || has_priv {
1606+
return ControlFlow::Break(UnsuitedInfo {
1607+
ty,
1608+
reason: if non_exhaustive {
1609+
UnsuitedReason::NonExhaustive
1610+
} else {
1611+
UnsuitedReason::PrivateField
1612+
},
1613+
});
1614+
}
1615+
}
1616+
if def.repr().c() {
1617+
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });
1618+
}
1619+
def.all_fields()
1620+
.map(|field| field.ty(tcx, args))
1621+
.try_for_each(|t| check_unsuited(tcx, typing_env, t))
1622+
}
1623+
_ => ControlFlow::Continue(()),
1624+
}
1625+
}
1626+
16401627
let mut prev_unsuited_1zst = false;
16411628
for field in field_infos {
1642-
if let Some(unsuited) = field.unsuited {
1643-
assert!(field.trivial);
1629+
if field.trivial
1630+
&& let Some(unsuited) = check_unsuited(tcx, typing_env, field.ty).break_value()
1631+
{
16441632
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
16451633
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
16461634
if non_trivial_count > 0 || prev_unsuited_1zst {

compiler/rustc_metadata/src/rmeta/table.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ impl IsDefault for UnusedGenericParams {
5555

5656
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
5757
/// Used mainly for Lazy positions and lengths.
58-
/// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
58+
///
59+
/// Invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
5960
/// but this has no impact on safety.
61+
/// In debug builds, this invariant is checked in `[TableBuilder::set]`
6062
pub(super) trait FixedSizeEncoding: IsDefault {
6163
/// This should be `[u8; BYTE_LEN]`;
6264
/// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations.
@@ -432,6 +434,13 @@ impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBui
432434
/// arises in the future then a new method (e.g. `clear` or `reset`) will need to be introduced
433435
/// for doing that explicitly.
434436
pub(crate) fn set(&mut self, i: I, value: T) {
437+
#[cfg(debug_assertions)]
438+
{
439+
debug_assert!(
440+
T::from_bytes(&[0; N]).is_default(),
441+
"expected all-zeroes to decode to the default value, as per the invariant of FixedSizeEncoding"
442+
);
443+
}
435444
if !value.is_default() {
436445
// FIXME(eddyb) investigate more compact encodings for sparse tables.
437446
// On the PR @michaelwoerister mentioned:

0 commit comments

Comments
 (0)