| author | bors <bors@rust-lang.org> 2026-06-02 16:07:57 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-02 16:07:57 UTC |
| log | 20e19eeac0c548e31f84d3914e0ce17cde618119 |
| tree | 74545378a4d344e416ca64a02bbebc72861065f6 |
| parent | 48f976c7131e76b6a1ba6ba316c90d97ffdfe184 |
| parent | 14cf0b6e2f96bad1dd9ce4cc5d6fd5d0d1cae20a |
Rollup of 6 pull requests
Successful merges:
- rust-lang/rust#155418 (transmute: fix check for whether newtypes have equal size)
- rust-lang/rust#156603 (Clarify E0381 diagnostics for branch conditions)
- rust-lang/rust#156643 (Document run-make external dependencies)
- rust-lang/rust#157009 (Avoid `unreachable_code` on required return values)
- rust-lang/rust#157308 (make typing mode exhaustive again...)
- rust-lang/rust#157312 (disallow most attrs on eiis)24 files changed, 462 insertions(+), 78 deletions(-)
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs+53-13| ... | ... | @@ -836,7 +836,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 836 | 836 | && !visitor |
| 837 | 837 | .errors |
| 838 | 838 | .iter() |
| 839 | .map(|(sp, _)| *sp) | |
| 839 | .map(|error| error.span) | |
| 840 | 840 | .any(|sp| span < sp && !sp.contains(span)) |
| 841 | 841 | }) { |
| 842 | 842 | show_assign_sugg = true; |
| ... | ... | @@ -865,8 +865,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 865 | 865 | err.span_label(span, format!("{path} {used} here but it {isnt_initialized}")); |
| 866 | 866 | |
| 867 | 867 | 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) { | |
| 870 | 871 | // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention |
| 871 | 872 | // match arms coming after the primary span because they aren't relevant: |
| 872 | 873 | // ``` |
| ... | ... | @@ -880,7 +881,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 880 | 881 | // _ => {} // We don't want to point to this. |
| 881 | 882 | // }; |
| 882 | 883 | // ``` |
| 883 | err.span_label(sp, label); | |
| 884 | shown_condition_value |= error.kind.describes_condition_value(); | |
| 885 | err.span_label(error.span, error.label); | |
| 884 | 886 | shown = true; |
| 885 | 887 | } |
| 886 | 888 | } |
| ... | ... | @@ -893,6 +895,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 893 | 895 | } |
| 894 | 896 | |
| 895 | 897 | 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 | } | |
| 896 | 904 | if show_assign_sugg { |
| 897 | 905 | struct LetVisitor { |
| 898 | 906 | decl_span: Span, |
| ... | ... | @@ -4680,7 +4688,31 @@ struct ConditionVisitor<'tcx> { |
| 4680 | 4688 | tcx: TyCtxt<'tcx>, |
| 4681 | 4689 | spans: Vec<Span>, |
| 4682 | 4690 | 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 | } | |
| 4684 | 4716 | } |
| 4685 | 4717 | |
| 4686 | 4718 | impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| ... | ... | @@ -4690,15 +4722,17 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| 4690 | 4722 | // `if` expressions with no `else` that initialize the binding might be missing an |
| 4691 | 4723 | // `else` arm. |
| 4692 | 4724 | if ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break() { |
| 4693 | self.errors.push(( | |
| 4725 | self.errors.push(ConditionError::new( | |
| 4694 | 4726 | cond.span, |
| 4727 | ConditionErrorKind::ConditionValue, | |
| 4695 | 4728 | format!( |
| 4696 | 4729 | "if this `if` condition is `false`, {} is not initialized", |
| 4697 | 4730 | self.name, |
| 4698 | 4731 | ), |
| 4699 | 4732 | )); |
| 4700 | self.errors.push(( | |
| 4733 | self.errors.push(ConditionError::new( | |
| 4701 | 4734 | ex.span.shrink_to_hi(), |
| 4735 | ConditionErrorKind::Other, | |
| 4702 | 4736 | format!("an `else` arm might be missing here, initializing {}", self.name), |
| 4703 | 4737 | )); |
| 4704 | 4738 | } |
| ... | ... | @@ -4712,8 +4746,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| 4712 | 4746 | (true, true) | (false, false) => {} |
| 4713 | 4747 | (true, false) => { |
| 4714 | 4748 | if other.span.is_desugaring(DesugaringKind::WhileLoop) { |
| 4715 | self.errors.push(( | |
| 4749 | self.errors.push(ConditionError::new( | |
| 4716 | 4750 | cond.span, |
| 4751 | ConditionErrorKind::ConditionValue, | |
| 4717 | 4752 | format!( |
| 4718 | 4753 | "if this condition isn't met and the `while` loop runs 0 \ |
| 4719 | 4754 | times, {} is not initialized", |
| ... | ... | @@ -4721,8 +4756,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| 4721 | 4756 | ), |
| 4722 | 4757 | )); |
| 4723 | 4758 | } else { |
| 4724 | self.errors.push(( | |
| 4759 | self.errors.push(ConditionError::new( | |
| 4725 | 4760 | body.span.shrink_to_hi().until(other.span), |
| 4761 | ConditionErrorKind::ConditionValue, | |
| 4726 | 4762 | format!( |
| 4727 | 4763 | "if the `if` condition is `false` and this `else` arm is \ |
| 4728 | 4764 | executed, {} is not initialized", |
| ... | ... | @@ -4732,8 +4768,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| 4732 | 4768 | } |
| 4733 | 4769 | } |
| 4734 | 4770 | (false, true) => { |
| 4735 | self.errors.push(( | |
| 4771 | self.errors.push(ConditionError::new( | |
| 4736 | 4772 | cond.span, |
| 4773 | ConditionErrorKind::ConditionValue, | |
| 4737 | 4774 | format!( |
| 4738 | 4775 | "if this condition is `true`, {} is not initialized", |
| 4739 | 4776 | self.name |
| ... | ... | @@ -4753,8 +4790,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| 4753 | 4790 | for (arm, seen) in arms.iter().zip(results) { |
| 4754 | 4791 | if !seen { |
| 4755 | 4792 | if loop_desugar == hir::MatchSource::ForLoopDesugar { |
| 4756 | self.errors.push(( | |
| 4793 | self.errors.push(ConditionError::new( | |
| 4757 | 4794 | e.span, |
| 4795 | ConditionErrorKind::Other, | |
| 4758 | 4796 | format!( |
| 4759 | 4797 | "if the `for` loop runs 0 times, {} is not initialized", |
| 4760 | 4798 | self.name |
| ... | ... | @@ -4767,8 +4805,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| 4767 | 4805 | ) { |
| 4768 | 4806 | continue; |
| 4769 | 4807 | } |
| 4770 | self.errors.push(( | |
| 4808 | self.errors.push(ConditionError::new( | |
| 4771 | 4809 | arm.pat.span.to(guard.span), |
| 4810 | ConditionErrorKind::ConditionValue, | |
| 4772 | 4811 | format!( |
| 4773 | 4812 | "if this pattern and condition are matched, {} is not \ |
| 4774 | 4813 | initialized", |
| ... | ... | @@ -4782,8 +4821,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { |
| 4782 | 4821 | ) { |
| 4783 | 4822 | continue; |
| 4784 | 4823 | } |
| 4785 | self.errors.push(( | |
| 4824 | self.errors.push(ConditionError::new( | |
| 4786 | 4825 | arm.pat.span, |
| 4826 | ConditionErrorKind::Other, | |
| 4787 | 4827 | format!( |
| 4788 | 4828 | "if this pattern is matched, {} is not initialized", |
| 4789 | 4829 | self.name |
compiler/rustc_builtin_macros/src/eii.rs+57-18| ... | ... | @@ -10,10 +10,10 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; |
| 10 | 10 | use thin_vec::{ThinVec, thin_vec}; |
| 11 | 11 | |
| 12 | 12 | 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, | |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | 19 | /// ```rust |
| ... | ... | @@ -128,6 +128,8 @@ fn eii_( |
| 128 | 128 | |
| 129 | 129 | let attrs_from_decl = |
| 130 | 130 | 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); | |
| 131 | 133 | |
| 132 | 134 | let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else { |
| 133 | 135 | // we don't need to wrap in Annotatable::Stmt conditionally since |
| ... | ... | @@ -148,6 +150,7 @@ fn eii_( |
| 148 | 150 | eii_attr_span, |
| 149 | 151 | item_span, |
| 150 | 152 | foreign_item_name, |
| 153 | default_func_attrs, | |
| 151 | 154 | )) |
| 152 | 155 | } |
| 153 | 156 | |
| ... | ... | @@ -157,7 +160,7 @@ fn eii_( |
| 157 | 160 | item_span, |
| 158 | 161 | kind, |
| 159 | 162 | vis, |
| 160 | &attrs_from_decl, | |
| 163 | foreign_item_attrs, | |
| 161 | 164 | )); |
| 162 | 165 | module_items.push(generate_attribute_macro_to_implement( |
| 163 | 166 | ecx, |
| ... | ... | @@ -165,7 +168,7 @@ fn eii_( |
| 165 | 168 | macro_name, |
| 166 | 169 | foreign_item_name, |
| 167 | 170 | impl_unsafe, |
| 168 | &attrs_from_decl, | |
| 171 | macro_attrs, | |
| 169 | 172 | )); |
| 170 | 173 | |
| 171 | 174 | // we don't need to wrap in Annotatable::Stmt conditionally since |
| ... | ... | @@ -173,6 +176,49 @@ fn eii_( |
| 173 | 176 | module_items.into_iter().map(Annotatable::Item).collect() |
| 174 | 177 | } |
| 175 | 178 | |
| 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 | ||
| 176 | 222 | /// Decide on the name of the macro that can be used to implement the EII. |
| 177 | 223 | /// This is either an explicitly given name, or the name of the item in the |
| 178 | 224 | /// declaration of the EII. |
| ... | ... | @@ -228,10 +274,8 @@ fn generate_default_func_impl( |
| 228 | 274 | eii_attr_span: Span, |
| 229 | 275 | item_span: Span, |
| 230 | 276 | foreign_item_name: Ident, |
| 277 | attrs: ThinVec<Attribute>, | |
| 231 | 278 | ) -> Box<ast::Item> { |
| 232 | // FIXME: re-add some original attrs | |
| 233 | let attrs = ThinVec::new(); | |
| 234 | ||
| 235 | 279 | let mut default_func = func.clone(); |
| 236 | 280 | default_func.eii_impls.push(EiiImpl { |
| 237 | 281 | node_id: DUMMY_NODE_ID, |
| ... | ... | @@ -289,10 +333,9 @@ fn generate_foreign_item( |
| 289 | 333 | item_span: Span, |
| 290 | 334 | item_kind: &ItemKind, |
| 291 | 335 | vis: Visibility, |
| 292 | attrs_from_decl: &[Attribute], | |
| 336 | attrs_from_decl: ThinVec<Attribute>, | |
| 293 | 337 | ) -> 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; | |
| 296 | 339 | |
| 297 | 340 | // Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled. |
| 298 | 341 | // 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( |
| 381 | 424 | macro_name: Ident, |
| 382 | 425 | foreign_item_name: Ident, |
| 383 | 426 | impl_unsafe: bool, |
| 384 | attrs_from_decl: &[Attribute], | |
| 427 | attrs_from_decl: ThinVec<Attribute>, | |
| 385 | 428 | ) -> 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; | |
| 391 | 430 | |
| 392 | 431 | // Avoid "missing stability attribute" errors for eiis in std. See #146993. |
| 393 | 432 | macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span)); |
compiler/rustc_builtin_macros/src/errors.rs+9| ... | ... | @@ -1186,6 +1186,15 @@ pub(crate) struct EiiMacroExpectedMaxOneArgument { |
| 1186 | 1186 | pub name: String, |
| 1187 | 1187 | } |
| 1188 | 1188 | |
| 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 | ||
| 1189 | 1198 | #[derive(Diagnostic)] |
| 1190 | 1199 | #[diag("named argument `{$named_arg_name}` is not used by name")] |
| 1191 | 1200 | pub(crate) struct NamedArgumentUsedPositionally { |
compiler/rustc_middle/src/ty/layout.rs+36-4| ... | ... | @@ -454,13 +454,42 @@ impl<'tcx> SizeSkeleton<'tcx> { |
| 454 | 454 | } |
| 455 | 455 | |
| 456 | 456 | ty::Adt(def, args) => { |
| 457 | // Only newtypes and enums w/ nullable pointer optimization. | |
| 457 | // Only newtypes and enums w/ nullable pointer optimization (NPO). | |
| 458 | 458 | if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 { |
| 459 | 459 | return Err(err); |
| 460 | 460 | } |
| 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 | } | |
| 461 | 488 | |
| 462 | 489 | // 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>>, _> { | |
| 464 | 493 | let i = VariantIdx::from_usize(i); |
| 465 | 494 | let fields = def.variant(i).fields.iter().map(|field| { |
| 466 | 495 | SizeSkeleton::compute_inner( |
| ... | ... | @@ -494,7 +523,8 @@ impl<'tcx> SizeSkeleton<'tcx> { |
| 494 | 523 | }; |
| 495 | 524 | |
| 496 | 525 | 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. | |
| 498 | 528 | if def.variants().len() == 1 { |
| 499 | 529 | if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 { |
| 500 | 530 | return Ok(SizeSkeleton::Pointer { non_zero, tail }); |
| ... | ... | @@ -504,7 +534,9 @@ impl<'tcx> SizeSkeleton<'tcx> { |
| 504 | 534 | } |
| 505 | 535 | |
| 506 | 536 | 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. | |
| 508 | 540 | match (v0, v1) { |
| 509 | 541 | (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None) |
| 510 | 542 | | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => { |
compiler/rustc_mir_build/src/builder/mod.rs+6| ... | ... | @@ -890,6 +890,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 890 | 890 | { |
| 891 | 891 | continue; |
| 892 | 892 | } |
| 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 | } | |
| 893 | 899 | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => { |
| 894 | 900 | continue; |
| 895 | 901 | } |
compiler/rustc_type_ir/src/infer_ctxt.rs+1| ... | ... | @@ -63,6 +63,7 @@ impl TypingModeErasedStatus for MayBeErased {} |
| 63 | 63 | feature = "nightly", |
| 64 | 64 | derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) |
| 65 | 65 | )] |
| 66 | #[cfg_attr(feature = "nightly", rustc_must_match_exhaustively)] | |
| 66 | 67 | pub enum TypingMode<I: Interner, S: TypingModeErasedStatus = MayBeErased> { |
| 67 | 68 | /// When checking whether impls overlap, we check whether any obligations |
| 68 | 69 | /// are guaranteed to never hold when unifying the impls. This requires us |
tests/run-make/README.md+34| ... | ... | @@ -22,5 +22,39 @@ The setup for the `rmake.rs` can be summarized as a 3-stage process: |
| 22 | 22 | and copy non-`rmake.rs` input support files over to `rmake_out/`. The support library is made available as an [*extern prelude*][extern_prelude]. |
| 23 | 23 | 3. Finally, we run the recipe binary and set `rmake_out/` as the working directory. |
| 24 | 24 | |
| 25 | ## External dependencies | |
| 26 | ||
| 27 | `compiletest` passes tool paths and target-specific flags to `rmake.rs` through | |
| 28 | environment variables. Prefer using the helpers in [`run_make_support`] over | |
| 29 | reading these variables directly. The helpers keep command construction | |
| 30 | consistent across hosts and targets, and avoid relying on whichever tools happen | |
| 31 | to be first in `PATH`. | |
| 32 | ||
| 33 | Commonly used helpers include: | |
| 34 | ||
| 35 | - `rustc()` and `rustdoc()` for the compiler and rustdoc under test, from | |
| 36 | `RUSTC` and `RUSTDOC`. | |
| 37 | - `cc()` and `cxx()` for the target C and C++ compilers, from `CC`/`CXX` plus | |
| 38 | `CC_DEFAULT_FLAGS`/`CXX_DEFAULT_FLAGS`. | |
| 39 | - `gcc()` for tests that specifically need `gcc`; unlike `cc()`, this assumes a | |
| 40 | suitable `gcc` is available in `PATH` and does not add `CC_DEFAULT_FLAGS`. | |
| 41 | - `llvm_ar()`, `llvm_nm()`, `llvm_objdump()`, `llvm_readobj()`, and similar | |
| 42 | LLVM tools from `LLVM_BIN_DIR`; `llvm_filecheck()` uses `LLVM_FILECHECK`. | |
| 43 | - `python_command()` for the Python interpreter selected by bootstrap, from | |
| 44 | `PYTHON`. | |
| 45 | - `clang()` for tests that explicitly require clang-based testing, from `CLANG`. | |
| 46 | - `cargo()` for in-tree cargo, from `CARGO`; this is only available in the | |
| 47 | `run-make-cargo` and `build-std` suites, not in plain `run-make`. | |
| 48 | - `htmldocck()` for the in-tree `src/etc/htmldocck.py` script, invoked through | |
| 49 | `python_command()`. | |
| 50 | ||
| 51 | Some of these variables are only set when the configured builder can provide the | |
| 52 | corresponding tool. Tests that require optional tools or LLVM target components | |
| 53 | should declare the matching compiletest directive, such as | |
| 54 | `//@ needs-force-clang-based-tests` or `//@ needs-llvm-components: x86`, instead | |
| 55 | of failing later in the recipe. If a test needs a tool that is not represented by | |
| 56 | `run_make_support::external_deps`, add a small helper there rather than open | |
| 57 | coding the lookup in individual tests. | |
| 58 | ||
| 25 | 59 | [`run_make_support`]: ../../src/tools/run-make-support |
| 26 | 60 | [extern_prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude |
tests/ui/async-await/no-non-guaranteed-initialization.stderr+2| ... | ... | @@ -10,6 +10,8 @@ LL | } |
| 10 | 10 | | - an `else` arm might be missing here, initializing `y` |
| 11 | 11 | LL | y |
| 12 | 12 | | ^ `y` used here but it is possibly-uninitialized |
| 13 | | | |
| 14 | = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown | |
| 13 | 15 | |
| 14 | 16 | error: aborting due to 1 previous error |
| 15 | 17 |
tests/ui/borrowck/borrowck-if-no-else.stderr+2| ... | ... | @@ -8,6 +8,8 @@ LL | let x: isize; if 1 > 2 { x = 10; } |
| 8 | 8 | | binding declared here but left uninitialized |
| 9 | 9 | LL | foo(x); |
| 10 | 10 | | ^ `x` used here but it is possibly-uninitialized |
| 11 | | | |
| 12 | = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown | |
| 11 | 13 | |
| 12 | 14 | error: aborting due to 1 previous error |
| 13 | 15 |
tests/ui/borrowck/borrowck-if-with-else.stderr+2| ... | ... | @@ -8,6 +8,8 @@ LL | if 1 > 2 { |
| 8 | 8 | ... |
| 9 | 9 | LL | foo(x); |
| 10 | 10 | | ^ `x` used here but it is possibly-uninitialized |
| 11 | | | |
| 12 | = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown | |
| 11 | 13 | |
| 12 | 14 | error: aborting due to 1 previous error |
| 13 | 15 |
tests/ui/borrowck/borrowck-while-break.stderr+2| ... | ... | @@ -8,6 +8,8 @@ LL | while cond { |
| 8 | 8 | ... |
| 9 | 9 | LL | println!("{}", v); |
| 10 | 10 | | ^ `v` used here but it is possibly-uninitialized |
| 11 | | | |
| 12 | = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown | |
| 11 | 13 | |
| 12 | 14 | error: aborting due to 1 previous error |
| 13 | 15 |
tests/ui/borrowck/borrowck-while.stderr+2| ... | ... | @@ -7,6 +7,8 @@ LL | while 1 == 1 { x = 10; } |
| 7 | 7 | | ------ if this condition isn't met and the `while` loop runs 0 times, `x` is not initialized |
| 8 | 8 | LL | return x; |
| 9 | 9 | | ^ `x` used here but it is possibly-uninitialized |
| 10 | | | |
| 11 | = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown | |
| 10 | 12 | |
| 11 | 13 | error: aborting due to 1 previous error |
| 12 | 14 |
tests/ui/borrowck/branch-condition-flow-issue-156494.rs created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | //@ edition: 2024 | |
| 2 | ||
| 3 | fn main() { | |
| 4 | let v1: Vec<i32> = vec![1, 2, 3]; | |
| 5 | let mut iter = v1.iter(); | |
| 6 | ||
| 7 | let mut first_encounter = true; | |
| 8 | let mut token: i32; | |
| 9 | let mut following_token: i32; | |
| 10 | loop { | |
| 11 | if first_encounter { | |
| 12 | if let Some(token) = iter.next() { | |
| 13 | match iter.next() { | |
| 14 | Some(temp) => { | |
| 15 | following_token = *temp; | |
| 16 | first_encounter = false; | |
| 17 | println!("{} followed by {}", token, following_token); | |
| 18 | } | |
| 19 | _ => { | |
| 20 | println!("{} is last", token); | |
| 21 | } | |
| 22 | } | |
| 23 | } else { | |
| 24 | break; | |
| 25 | } | |
| 26 | } else { | |
| 27 | token = following_token; //~ ERROR used binding `following_token` isn't initialized | |
| 28 | first_encounter = true; | |
| 29 | match iter.next() { | |
| 30 | Some(temp) => { | |
| 31 | following_token = *temp; | |
| 32 | first_encounter = false; | |
| 33 | println!("{} followed by {}", token, following_token); | |
| 34 | } | |
| 35 | _ => { | |
| 36 | println!("{} is last", token); | |
| 37 | } | |
| 38 | } | |
| 39 | } | |
| 40 | } | |
| 41 | } | |
| 42 | ||
| 43 | fn guarded_match(value: i32, condition: bool) { | |
| 44 | let y; | |
| 45 | match value { | |
| 46 | 0 => { | |
| 47 | y = 1; | |
| 48 | } | |
| 49 | _ if condition => {} | |
| 50 | _ => { | |
| 51 | y = 2; | |
| 52 | } | |
| 53 | } | |
| 54 | let _z = y; //~ ERROR used binding `y` is possibly-uninitialized | |
| 55 | } |
tests/ui/borrowck/branch-condition-flow-issue-156494.stderr created+38| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | error[E0381]: used binding `following_token` isn't initialized | |
| 2 | --> $DIR/branch-condition-flow-issue-156494.rs:27:21 | |
| 3 | | | |
| 4 | LL | let mut following_token: i32; | |
| 5 | | ------------------- binding declared here but left uninitialized | |
| 6 | ... | |
| 7 | LL | _ => { | |
| 8 | | - if this pattern is matched, `following_token` is not initialized | |
| 9 | ... | |
| 10 | LL | } else { | |
| 11 | | ------ if the `if` condition is `false` and this `else` arm is executed, `following_token` is not initialized | |
| 12 | ... | |
| 13 | LL | token = following_token; | |
| 14 | | ^^^^^^^^^^^^^^^ `following_token` used here but it isn't initialized | |
| 15 | | | |
| 16 | = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown | |
| 17 | help: consider assigning a value | |
| 18 | | | |
| 19 | LL | let mut following_token: i32 = 42; | |
| 20 | | ++++ | |
| 21 | ||
| 22 | error[E0381]: used binding `y` is possibly-uninitialized | |
| 23 | --> $DIR/branch-condition-flow-issue-156494.rs:54:14 | |
| 24 | | | |
| 25 | LL | let y; | |
| 26 | | - binding declared here but left uninitialized | |
| 27 | ... | |
| 28 | LL | _ if condition => {} | |
| 29 | | -------------- if this pattern and condition are matched, `y` is not initialized | |
| 30 | ... | |
| 31 | LL | let _z = y; | |
| 32 | | ^ `y` used here but it is possibly-uninitialized | |
| 33 | | | |
| 34 | = note: when checking initialization, the compiler describes possible control-flow paths without evaluating whether branch conditions can actually have the values shown | |
| 35 | ||
| 36 | error: aborting due to 2 previous errors | |
| 37 | ||
| 38 | For more information about this error, try `rustc --explain E0381`. |
tests/ui/eii/attrs.rs created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | #![feature(extern_item_impls)] | |
| 2 | #![deny(deprecated)] //~ NOTE: | |
| 3 | ||
| 4 | // makes no sense on functions, nor on the macro generated (it's a macrov2). | |
| 5 | #[macro_export] //~ NOTE: this attribute is not supported | |
| 6 | // makes sense, as long as we only forward it onto the function, | |
| 7 | // so we allow and this shouln't cause errors for being on a "wrong target". | |
| 8 | #[inline] | |
| 9 | // makes sense, should be allowed, and forwarded on both the function and the macro | |
| 10 | #[deprecated = "foo"] | |
| 11 | #[eii] | |
| 12 | fn example() {} | |
| 13 | //~^ ERROR only a small subset of attributes are supported on externally implementable items | |
| 14 | ||
| 15 | // check that both are deprecated vvvv | |
| 16 | #[example] | |
| 17 | //~^ ERROR use of deprecated macro | |
| 18 | fn explicit_impl() {} | |
| 19 | fn main() { | |
| 20 | example() | |
| 21 | //~^ ERROR use of deprecated function | |
| 22 | } |
tests/ui/eii/attrs.stderr created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | error: only a small subset of attributes are supported on externally implementable items | |
| 2 | --> $DIR/attrs.rs:12:1 | |
| 3 | | | |
| 4 | LL | fn example() {} | |
| 5 | | ^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | note: this attribute is not supported | |
| 8 | --> $DIR/attrs.rs:5:1 | |
| 9 | | | |
| 10 | LL | #[macro_export] | |
| 11 | | ^^^^^^^^^^^^^^^ | |
| 12 | ||
| 13 | error: use of deprecated macro `example`: foo | |
| 14 | --> $DIR/attrs.rs:16:3 | |
| 15 | | | |
| 16 | LL | #[example] | |
| 17 | | ^^^^^^^ | |
| 18 | | | |
| 19 | note: the lint level is defined here | |
| 20 | --> $DIR/attrs.rs:2:9 | |
| 21 | | | |
| 22 | LL | #![deny(deprecated)] | |
| 23 | | ^^^^^^^^^^ | |
| 24 | ||
| 25 | error: use of deprecated function `example`: foo | |
| 26 | --> $DIR/attrs.rs:20:5 | |
| 27 | | | |
| 28 | LL | example() | |
| 29 | | ^^^^^^^ | |
| 30 | ||
| 31 | error: aborting due to 3 previous errors | |
| 32 |
tests/ui/eii/ice_contract_attr_on_eii_generated_item.rs deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | //@ compile-flags: --crate-type rlib | |
| 2 | ||
| 3 | #![feature(extern_item_impls)] | |
| 4 | #![feature(contracts)] | |
| 5 | #![allow(incomplete_features)] | |
| 6 | ||
| 7 | #[eii] | |
| 8 | #[core::contracts::ensures] | |
| 9 | //~^ ERROR contract annotations is only supported in functions with bodies | |
| 10 | //~| ERROR contract annotations can only be used on functions | |
| 11 | fn implementation(); |
tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | error: contract annotations is only supported in functions with bodies | |
| 2 | --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1 | |
| 3 | | | |
| 4 | LL | #[core::contracts::ensures] | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | ||
| 7 | error: contract annotations can only be used on functions | |
| 8 | --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1 | |
| 9 | | | |
| 10 | LL | #[core::contracts::ensures] | |
| 11 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 12 | ||
| 13 | error: aborting due to 2 previous errors | |
| 14 |
tests/ui/transmute/raw-ptr-non-null.rs deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | //! After the use of pattern types inside `NonNull`, | |
| 2 | //! transmuting between a niche optimized enum wrapping a | |
| 3 | //! generic `NonNull` and raw pointers stopped working. | |
| 4 | //@ check-pass | |
| 5 | ||
| 6 | use std::ptr::NonNull; | |
| 7 | pub const fn is_null<'a, T: ?Sized>(ptr: *const T) -> bool { | |
| 8 | unsafe { matches!(core::mem::transmute::<*const T, Option<NonNull<T>>>(ptr), None) } | |
| 9 | } | |
| 10 | ||
| 11 | fn main() {} |
tests/ui/transmute/transmute-different-sizes.rs+32| ... | ... | @@ -48,4 +48,36 @@ pub unsafe fn shouldnt_work2<T: ?Sized>(from: *mut T) -> PtrAndEmptyArray<T> { |
| 48 | 48 | //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | #[repr(align(16))] | |
| 52 | struct OverAlignWrap<T>(T); | |
| 53 | ||
| 54 | fn shouldnt_work3<T: ?Sized>(x: OverAlignWrap<*const T>) -> *const T { | |
| 55 | unsafe { transmute(x) } | |
| 56 | //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types | |
| 57 | } | |
| 58 | ||
| 59 | // With `repr(C)`, this type has a disriminant, so it does not have the same size as `T`. | |
| 60 | #[repr(C)] | |
| 61 | enum NotANewtype<T> { | |
| 62 | SingleVariant(T), | |
| 63 | } | |
| 64 | ||
| 65 | fn shouldnt_work4<T: ?Sized>(x: &T) -> NotANewtype<&T> { | |
| 66 | unsafe { transmute(x) } | |
| 67 | //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types | |
| 68 | } | |
| 69 | ||
| 70 | // With `repr(C)`, this type has a disriminant; NPO does not kick in. | |
| 71 | // Therefore this is always bigger than `T`. | |
| 72 | #[repr(C)] | |
| 73 | enum NotNullPointerOptimized<T> { | |
| 74 | Some(T), | |
| 75 | None | |
| 76 | } | |
| 77 | ||
| 78 | fn shouldnt_work5<T: ?Sized>(x: &T) -> NotNullPointerOptimized<&T> { | |
| 79 | unsafe { transmute(x) } | |
| 80 | //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types | |
| 81 | } | |
| 82 | ||
| 51 | 83 | fn main() {} |
tests/ui/transmute/transmute-different-sizes.stderr+28-1| ... | ... | @@ -43,6 +43,33 @@ LL | std::mem::transmute(from) |
| 43 | 43 | = note: source type: `*mut T` (pointer to `T`) |
| 44 | 44 | = note: target type: `PtrAndEmptyArray<T>` (size can vary because of <T as Pointee>::Metadata) |
| 45 | 45 | |
| 46 | error: aborting due to 5 previous errors | |
| 46 | error[E0512]: cannot transmute between types of different sizes, or dependently-sized types | |
| 47 | --> $DIR/transmute-different-sizes.rs:55:14 | |
| 48 | | | |
| 49 | LL | unsafe { transmute(x) } | |
| 50 | | ^^^^^^^^^ | |
| 51 | | | |
| 52 | = note: source type: `OverAlignWrap<*const T>` (size can vary because of <T as Pointee>::Metadata) | |
| 53 | = note: target type: `*const T` (pointer to `T`) | |
| 54 | ||
| 55 | error[E0512]: cannot transmute between types of different sizes, or dependently-sized types | |
| 56 | --> $DIR/transmute-different-sizes.rs:66:14 | |
| 57 | | | |
| 58 | LL | unsafe { transmute(x) } | |
| 59 | | ^^^^^^^^^ | |
| 60 | | | |
| 61 | = note: source type: `&T` (pointer to `T`) | |
| 62 | = note: target type: `NotANewtype<&T>` (size can vary because of <T as Pointee>::Metadata) | |
| 63 | ||
| 64 | error[E0512]: cannot transmute between types of different sizes, or dependently-sized types | |
| 65 | --> $DIR/transmute-different-sizes.rs:79:14 | |
| 66 | | | |
| 67 | LL | unsafe { transmute(x) } | |
| 68 | | ^^^^^^^^^ | |
| 69 | | | |
| 70 | = note: source type: `&T` (pointer to `T`) | |
| 71 | = note: target type: `NotNullPointerOptimized<&T>` (size can vary because of <T as Pointee>::Metadata) | |
| 72 | ||
| 73 | error: aborting due to 8 previous errors | |
| 47 | 74 | |
| 48 | 75 | For more information about this error, try `rustc --explain E0512`. |
tests/ui/transmute/transmute-fat-pointers.rs+35-2| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | #![allow(dead_code)] |
| 6 | 6 | |
| 7 | 7 | use std::mem::transmute; |
| 8 | use std::ptr::NonNull; | |
| 8 | 9 | |
| 9 | 10 | fn a<T, U: ?Sized>(x: &[T]) -> &U { |
| 10 | 11 | unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes |
| ... | ... | @@ -15,11 +16,11 @@ fn b<T: ?Sized, U: ?Sized>(x: &T) -> &U { |
| 15 | 16 | } |
| 16 | 17 | |
| 17 | 18 | fn c<T, U>(x: &T) -> &U { |
| 18 | unsafe { transmute(x) } | |
| 19 | unsafe { transmute(x) } // Ok! | |
| 19 | 20 | } |
| 20 | 21 | |
| 21 | 22 | fn d<T, U>(x: &[T]) -> &[U] { |
| 22 | unsafe { transmute(x) } | |
| 23 | unsafe { transmute(x) } // Ok! | |
| 23 | 24 | } |
| 24 | 25 | |
| 25 | 26 | fn e<T: ?Sized, U>(x: &T) -> &U { |
| ... | ... | @@ -30,4 +31,36 @@ fn f<T, U: ?Sized>(x: &T) -> &U { |
| 30 | 31 | unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes |
| 31 | 32 | } |
| 32 | 33 | |
| 34 | // We can transmute even between pointers of unknown size as long as the metadata of | |
| 35 | // input and output type are the same. This even accounts for null pointer optimizations. | |
| 36 | fn g1<T: ?Sized>(x: &T) -> Option<&T> { | |
| 37 | unsafe { transmute(x) } // Ok! | |
| 38 | } | |
| 39 | ||
| 40 | fn g2<T: ?Sized>(x: Option<NonNull<T>>) -> NonNull<T> { | |
| 41 | unsafe { transmute(x) } // Ok! | |
| 42 | } | |
| 43 | ||
| 44 | fn g3<T: ?Sized>(x: *const T) -> Option<NonNull<T>> { | |
| 45 | unsafe { transmute(x) } // Ok! | |
| 46 | } | |
| 47 | ||
| 48 | // Make sure we can see through all the layers of `Box`. | |
| 49 | fn h<T: ?Sized>(x: Box<T>) -> &'static T { | |
| 50 | unsafe { transmute(x) } // Ok! | |
| 51 | } | |
| 52 | ||
| 53 | // Make sure we can see through newtype wrappers. | |
| 54 | struct Wrapper1<T>(T); | |
| 55 | ||
| 56 | #[repr(C)] | |
| 57 | struct Wrapper2<T>(T); | |
| 58 | ||
| 59 | fn i1<T: ?Sized>(x: &T) -> Wrapper1<&T> { | |
| 60 | unsafe { transmute(x) } // Ok! | |
| 61 | } | |
| 62 | fn i2<T: ?Sized>(x: &T) -> Wrapper2<&T> { | |
| 63 | unsafe { transmute(x) } // Ok! | |
| 64 | } | |
| 65 | ||
| 33 | 66 | fn main() { } |
tests/ui/transmute/transmute-fat-pointers.stderr+4-4| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error[E0512]: cannot transmute between types of different sizes, or dependently-sized types |
| 2 | --> $DIR/transmute-fat-pointers.rs:10:14 | |
| 2 | --> $DIR/transmute-fat-pointers.rs:11:14 | |
| 3 | 3 | | |
| 4 | 4 | LL | unsafe { transmute(x) } |
| 5 | 5 | | ^^^^^^^^^ |
| ... | ... | @@ -8,7 +8,7 @@ LL | unsafe { transmute(x) } |
| 8 | 8 | = note: target type: `&U` (pointer to `U`) |
| 9 | 9 | |
| 10 | 10 | error[E0512]: cannot transmute between types of different sizes, or dependently-sized types |
| 11 | --> $DIR/transmute-fat-pointers.rs:14:14 | |
| 11 | --> $DIR/transmute-fat-pointers.rs:15:14 | |
| 12 | 12 | | |
| 13 | 13 | LL | unsafe { transmute(x) } |
| 14 | 14 | | ^^^^^^^^^ |
| ... | ... | @@ -17,7 +17,7 @@ LL | unsafe { transmute(x) } |
| 17 | 17 | = note: target type: `&U` (pointer to `U`) |
| 18 | 18 | |
| 19 | 19 | error[E0512]: cannot transmute between types of different sizes, or dependently-sized types |
| 20 | --> $DIR/transmute-fat-pointers.rs:26:14 | |
| 20 | --> $DIR/transmute-fat-pointers.rs:27:14 | |
| 21 | 21 | | |
| 22 | 22 | LL | unsafe { transmute(x) } |
| 23 | 23 | | ^^^^^^^^^ |
| ... | ... | @@ -26,7 +26,7 @@ LL | unsafe { transmute(x) } |
| 26 | 26 | = note: target type: `&U` (N bits) |
| 27 | 27 | |
| 28 | 28 | error[E0512]: cannot transmute between types of different sizes, or dependently-sized types |
| 29 | --> $DIR/transmute-fat-pointers.rs:30:14 | |
| 29 | --> $DIR/transmute-fat-pointers.rs:31:14 | |
| 30 | 30 | | |
| 31 | 31 | LL | unsafe { transmute(x) } |
| 32 | 32 | | ^^^^^^^^^ |
tests/ui/uninhabited/unreachable.rs+10| ... | ... | @@ -4,6 +4,8 @@ |
| 4 | 4 | //@ check-pass |
| 5 | 5 | #![deny(unreachable_code)] |
| 6 | 6 | |
| 7 | use std::process::ExitCode; | |
| 8 | ||
| 7 | 9 | enum Never {} |
| 8 | 10 | |
| 9 | 11 | fn make_never() -> Never { |
| ... | ... | @@ -28,6 +30,14 @@ fn branchy() { |
| 28 | 30 | } |
| 29 | 31 | } |
| 30 | 32 | |
| 33 | // Regression test for https://github.com/rust-lang/rust/issues/152559. | |
| 34 | // The final expression is unreachable at runtime, but it cannot be removed | |
| 35 | // because it supplies the function's required return type. | |
| 36 | fn required_return_value() -> ExitCode { | |
| 37 | make_never(); | |
| 38 | ExitCode::FAILURE | |
| 39 | } | |
| 40 | ||
| 31 | 41 | fn main() { |
| 32 | 42 | func(); |
| 33 | 43 | block(); |