Skip to content

Commit 20e19ee

Browse files
committed
Auto merge of rust-lang#157320 - JonathanBrouwer:rollup-ECUZfbo, r=JonathanBrouwer
Rollup of 6 pull requests Successful merges: - rust-lang#155418 (transmute: fix check for whether newtypes have equal size) - rust-lang#156603 (Clarify E0381 diagnostics for branch conditions) - rust-lang#156643 (Document run-make external dependencies) - rust-lang#157009 (Avoid `unreachable_code` on required return values) - rust-lang#157308 (make typing mode exhaustive again...) - rust-lang#157312 (disallow most attrs on eiis)
2 parents 48f976c + 14cf0b6 commit 20e19ee

24 files changed

Lines changed: 462 additions & 78 deletions

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
836836
&& !visitor
837837
.errors
838838
.iter()
839-
.map(|(sp, _)| *sp)
839+
.map(|error| error.span)
840840
.any(|sp| span < sp && !sp.contains(span))
841841
}) {
842842
show_assign_sugg = true;
@@ -865,8 +865,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
865865
err.span_label(span, format!("{path} {used} here but it {isnt_initialized}"));
866866

867867
let mut shown = false;
868-
for (sp, label) in visitor.errors {
869-
if sp < span && !sp.overlaps(span) {
868+
let mut shown_condition_value = false;
869+
for error in visitor.errors {
870+
if error.span < span && !error.span.overlaps(span) {
870871
// When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention
871872
// match arms coming after the primary span because they aren't relevant:
872873
// ```
@@ -880,7 +881,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
880881
// _ => {} // We don't want to point to this.
881882
// };
882883
// ```
883-
err.span_label(sp, label);
884+
shown_condition_value |= error.kind.describes_condition_value();
885+
err.span_label(error.span, error.label);
884886
shown = true;
885887
}
886888
}
@@ -893,6 +895,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
893895
}
894896

895897
err.span_label(decl_span, "binding declared here but left uninitialized");
898+
if shown_condition_value {
899+
err.note(
900+
"when checking initialization, the compiler describes possible control-flow paths \
901+
without evaluating whether branch conditions can actually have the values shown",
902+
);
903+
}
896904
if show_assign_sugg {
897905
struct LetVisitor {
898906
decl_span: Span,
@@ -4680,7 +4688,31 @@ struct ConditionVisitor<'tcx> {
46804688
tcx: TyCtxt<'tcx>,
46814689
spans: Vec<Span>,
46824690
name: String,
4683-
errors: Vec<(Span, String)>,
4691+
errors: Vec<ConditionError>,
4692+
}
4693+
4694+
struct ConditionError {
4695+
span: Span,
4696+
label: String,
4697+
kind: ConditionErrorKind,
4698+
}
4699+
4700+
impl ConditionError {
4701+
fn new(span: Span, kind: ConditionErrorKind, label: String) -> Self {
4702+
Self { span, label, kind }
4703+
}
4704+
}
4705+
4706+
#[derive(Clone, Copy)]
4707+
enum ConditionErrorKind {
4708+
ConditionValue,
4709+
Other,
4710+
}
4711+
4712+
impl ConditionErrorKind {
4713+
fn describes_condition_value(self) -> bool {
4714+
matches!(self, Self::ConditionValue)
4715+
}
46844716
}
46854717

46864718
impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
@@ -4690,15 +4722,17 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
46904722
// `if` expressions with no `else` that initialize the binding might be missing an
46914723
// `else` arm.
46924724
if ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break() {
4693-
self.errors.push((
4725+
self.errors.push(ConditionError::new(
46944726
cond.span,
4727+
ConditionErrorKind::ConditionValue,
46954728
format!(
46964729
"if this `if` condition is `false`, {} is not initialized",
46974730
self.name,
46984731
),
46994732
));
4700-
self.errors.push((
4733+
self.errors.push(ConditionError::new(
47014734
ex.span.shrink_to_hi(),
4735+
ConditionErrorKind::Other,
47024736
format!("an `else` arm might be missing here, initializing {}", self.name),
47034737
));
47044738
}
@@ -4712,17 +4746,19 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
47124746
(true, true) | (false, false) => {}
47134747
(true, false) => {
47144748
if other.span.is_desugaring(DesugaringKind::WhileLoop) {
4715-
self.errors.push((
4749+
self.errors.push(ConditionError::new(
47164750
cond.span,
4751+
ConditionErrorKind::ConditionValue,
47174752
format!(
47184753
"if this condition isn't met and the `while` loop runs 0 \
47194754
times, {} is not initialized",
47204755
self.name
47214756
),
47224757
));
47234758
} else {
4724-
self.errors.push((
4759+
self.errors.push(ConditionError::new(
47254760
body.span.shrink_to_hi().until(other.span),
4761+
ConditionErrorKind::ConditionValue,
47264762
format!(
47274763
"if the `if` condition is `false` and this `else` arm is \
47284764
executed, {} is not initialized",
@@ -4732,8 +4768,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
47324768
}
47334769
}
47344770
(false, true) => {
4735-
self.errors.push((
4771+
self.errors.push(ConditionError::new(
47364772
cond.span,
4773+
ConditionErrorKind::ConditionValue,
47374774
format!(
47384775
"if this condition is `true`, {} is not initialized",
47394776
self.name
@@ -4753,8 +4790,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
47534790
for (arm, seen) in arms.iter().zip(results) {
47544791
if !seen {
47554792
if loop_desugar == hir::MatchSource::ForLoopDesugar {
4756-
self.errors.push((
4793+
self.errors.push(ConditionError::new(
47574794
e.span,
4795+
ConditionErrorKind::Other,
47584796
format!(
47594797
"if the `for` loop runs 0 times, {} is not initialized",
47604798
self.name
@@ -4767,8 +4805,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
47674805
) {
47684806
continue;
47694807
}
4770-
self.errors.push((
4808+
self.errors.push(ConditionError::new(
47714809
arm.pat.span.to(guard.span),
4810+
ConditionErrorKind::ConditionValue,
47724811
format!(
47734812
"if this pattern and condition are matched, {} is not \
47744813
initialized",
@@ -4782,8 +4821,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
47824821
) {
47834822
continue;
47844823
}
4785-
self.errors.push((
4824+
self.errors.push(ConditionError::new(
47864825
arm.pat.span,
4826+
ConditionErrorKind::Other,
47874827
format!(
47884828
"if this pattern is matched, {} is not initialized",
47894829
self.name

compiler/rustc_builtin_macros/src/eii.rs

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
1010
use thin_vec::{ThinVec, thin_vec};
1111

1212
use crate::errors::{
13-
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
14-
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition,
15-
EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault,
16-
EiiStaticMultipleImplementations, EiiStaticMutable,
13+
EiiAttributeNotSupported, EiiExternTargetExpectedList, EiiExternTargetExpectedMacro,
14+
EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce,
15+
EiiSharedMacroInStatementPosition, EiiSharedMacroTarget, EiiStaticArgumentRequired,
16+
EiiStaticDefault, EiiStaticMultipleImplementations, EiiStaticMutable,
1717
};
1818

1919
/// ```rust
@@ -128,6 +128,8 @@ fn eii_(
128128

129129
let attrs_from_decl =
130130
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
131+
let (macro_attrs, foreign_item_attrs, default_func_attrs) =
132+
split_attrs(ecx, item_span, attrs_from_decl);
131133

132134
let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else {
133135
// we don't need to wrap in Annotatable::Stmt conditionally since
@@ -148,6 +150,7 @@ fn eii_(
148150
eii_attr_span,
149151
item_span,
150152
foreign_item_name,
153+
default_func_attrs,
151154
))
152155
}
153156

@@ -157,22 +160,65 @@ fn eii_(
157160
item_span,
158161
kind,
159162
vis,
160-
&attrs_from_decl,
163+
foreign_item_attrs,
161164
));
162165
module_items.push(generate_attribute_macro_to_implement(
163166
ecx,
164167
eii_attr_span,
165168
macro_name,
166169
foreign_item_name,
167170
impl_unsafe,
168-
&attrs_from_decl,
171+
macro_attrs,
169172
));
170173

171174
// we don't need to wrap in Annotatable::Stmt conditionally since
172175
// EII can't be used on items in statement position
173176
module_items.into_iter().map(Annotatable::Item).collect()
174177
}
175178

179+
fn split_attrs(
180+
ecx: &mut ExtCtxt<'_>,
181+
span: Span,
182+
attrs: ThinVec<Attribute>,
183+
) -> (ThinVec<Attribute>, ThinVec<Attribute>, ThinVec<Attribute>) {
184+
let mut macro_attributes = ThinVec::new();
185+
let mut foreign_item_attributes = ThinVec::new();
186+
let mut default_attributes = ThinVec::new();
187+
188+
for attr in attrs {
189+
match attr.name() {
190+
// Inline only matters for the default function being inlined into callsites
191+
Some(sym::inline) => default_attributes.push(attr),
192+
// If an eii is marked a lang item, that's because we want to call its declaration, so
193+
// mark the foreign item as the lang item
194+
Some(sym::lang) => foreign_item_attributes.push(attr),
195+
// Deprecating an eii means deprecating the macro and the foreign item
196+
Some(sym::deprecated) => {
197+
foreign_item_attributes.push(attr.clone());
198+
macro_attributes.push(attr);
199+
}
200+
// The stability of an EII affects the usage of the macro and calling the foreign item
201+
Some(sym::stable) | Some(sym::unstable) => {
202+
foreign_item_attributes.push(attr.clone());
203+
macro_attributes.push(attr);
204+
}
205+
// Doc attributes should be forwarded to the macro and the foreign item, since those are
206+
// the two items you interact with as a user.
207+
// FIXME: idk yet how EIIs show up in docs, might want to customize
208+
_ if attr.is_doc_comment() => {
209+
foreign_item_attributes.push(attr.clone());
210+
macro_attributes.push(attr);
211+
}
212+
Some(sym::eii) => unreachable!("should already be filtered out"),
213+
_ => {
214+
ecx.dcx().emit_err(EiiAttributeNotSupported { span, attr_span: attr.span() });
215+
}
216+
}
217+
}
218+
219+
(macro_attributes, foreign_item_attributes, default_attributes)
220+
}
221+
176222
/// Decide on the name of the macro that can be used to implement the EII.
177223
/// This is either an explicitly given name, or the name of the item in the
178224
/// declaration of the EII.
@@ -228,10 +274,8 @@ fn generate_default_func_impl(
228274
eii_attr_span: Span,
229275
item_span: Span,
230276
foreign_item_name: Ident,
277+
attrs: ThinVec<Attribute>,
231278
) -> Box<ast::Item> {
232-
// FIXME: re-add some original attrs
233-
let attrs = ThinVec::new();
234-
235279
let mut default_func = func.clone();
236280
default_func.eii_impls.push(EiiImpl {
237281
node_id: DUMMY_NODE_ID,
@@ -289,10 +333,9 @@ fn generate_foreign_item(
289333
item_span: Span,
290334
item_kind: &ItemKind,
291335
vis: Visibility,
292-
attrs_from_decl: &[Attribute],
336+
attrs_from_decl: ThinVec<Attribute>,
293337
) -> Box<ast::Item> {
294-
let mut foreign_item_attrs = ThinVec::new();
295-
foreign_item_attrs.extend_from_slice(attrs_from_decl);
338+
let mut foreign_item_attrs = attrs_from_decl;
296339

297340
// Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled.
298341
// This attribute makes sure that we later know that this foreign item's symbol should not be.
@@ -381,13 +424,9 @@ fn generate_attribute_macro_to_implement(
381424
macro_name: Ident,
382425
foreign_item_name: Ident,
383426
impl_unsafe: bool,
384-
attrs_from_decl: &[Attribute],
427+
attrs_from_decl: ThinVec<Attribute>,
385428
) -> Box<ast::Item> {
386-
let mut macro_attrs = ThinVec::new();
387-
388-
// To avoid e.g. `error: attribute macro has missing stability attribute`
389-
// errors for eii's in std.
390-
macro_attrs.extend_from_slice(attrs_from_decl);
429+
let mut macro_attrs = attrs_from_decl;
391430

392431
// Avoid "missing stability attribute" errors for eiis in std. See #146993.
393432
macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span));

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,15 @@ pub(crate) struct EiiMacroExpectedMaxOneArgument {
11861186
pub name: String,
11871187
}
11881188

1189+
#[derive(Diagnostic)]
1190+
#[diag("only a small subset of attributes are supported on externally implementable items")]
1191+
pub(crate) struct EiiAttributeNotSupported {
1192+
#[primary_span]
1193+
pub span: Span,
1194+
#[note("this attribute is not supported")]
1195+
pub attr_span: Span,
1196+
}
1197+
11891198
#[derive(Diagnostic)]
11901199
#[diag("named argument `{$named_arg_name}` is not used by name")]
11911200
pub(crate) struct NamedArgumentUsedPositionally {

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,13 +454,42 @@ impl<'tcx> SizeSkeleton<'tcx> {
454454
}
455455

456456
ty::Adt(def, args) => {
457-
// Only newtypes and enums w/ nullable pointer optimization.
457+
// Only newtypes and enums w/ nullable pointer optimization (NPO).
458458
if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
459459
return Err(err);
460460
}
461+
// Only default repr types.
462+
{
463+
// We can ignore the seed and some particular flags that can never affect the
464+
// layout of newtypes / NPO types, but we have to check everything else.
465+
// If you are adding a new field to `ReprOptions`, make sure to extend the check
466+
// below so that we bail out if it is not at its default value!
467+
let ReprOptions { int, align, pack, flags, scalable, field_shuffle_seed: _ } =
468+
def.repr();
469+
let mut ignored_flags = ReprFlags::IS_TRANSPARENT
470+
| ReprFlags::IS_LINEAR
471+
| ReprFlags::RANDOMIZE_LAYOUT;
472+
if def.is_struct() {
473+
// `repr(C)` is only okay for structs, not for enums.
474+
// Below, the *only* thing we do for structs is propagating
475+
// `SizeSkeleton::Pointer`. We do *not* assume that `repr(C)` preserved
476+
// ZST-ness (which might stop being true eventually).
477+
ignored_flags |= ReprFlags::IS_C;
478+
}
479+
if int.is_some()
480+
|| align.is_some()
481+
|| pack.is_some()
482+
|| flags.difference(ignored_flags) != ReprFlags::default()
483+
|| scalable.is_some()
484+
{
485+
return Err(err);
486+
}
487+
}
461488

462489
// Get a zero-sized variant or a pointer newtype.
463-
let zero_or_ptr_variant = |i| {
490+
// Returns `Ok(None)` for 1-ZST types, `Ok(Some)` if (ignoring all 1-ZST fields)
491+
// there's just a single pointer, and `Err` otherwise.
492+
let zero_or_ptr_variant = |i| -> Result<Option<SizeSkeleton<'tcx>>, _> {
464493
let i = VariantIdx::from_usize(i);
465494
let fields = def.variant(i).fields.iter().map(|field| {
466495
SizeSkeleton::compute_inner(
@@ -494,7 +523,8 @@ impl<'tcx> SizeSkeleton<'tcx> {
494523
};
495524

496525
let v0 = zero_or_ptr_variant(0)?;
497-
// Newtype.
526+
// Single-variant case: Check if this is a newtype around a pointer.
527+
// Such types are themselves pointer-sized.
498528
if def.variants().len() == 1 {
499529
if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
500530
return Ok(SizeSkeleton::Pointer { non_zero, tail });
@@ -504,7 +534,9 @@ impl<'tcx> SizeSkeleton<'tcx> {
504534
}
505535

506536
let v1 = zero_or_ptr_variant(1)?;
507-
// Nullable pointer enum optimization.
537+
// 2-variant case: Check if one variant is a *non-zero* pointer and the other a
538+
// 1-ZST. Such types are eligible to for the nullable pointer enum optimization, so
539+
// they are themselves pointer-sized.
508540
match (v0, v1) {
509541
(Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
510542
| (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {

compiler/rustc_mir_build/src/builder/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
890890
{
891891
continue;
892892
}
893+
// Ignore return value plumbing. After a call returning a non-`!`
894+
// uninhabited type, a tail expression can be unreachable while
895+
// still being needed to satisfy the surrounding return type.
896+
StatementKind::Assign((place, _)) if place.as_local() == Some(RETURN_PLACE) => {
897+
continue;
898+
}
893899
StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => {
894900
continue;
895901
}

0 commit comments

Comments
 (0)