authorbors <bors@rust-lang.org> 2026-06-02 16:07:57 UTC
committerbors <bors@rust-lang.org> 2026-06-02 16:07:57 UTC
log20e19eeac0c548e31f84d3914e0ce17cde618119
tree74545378a4d344e416ca64a02bbebc72861065f6
parent48f976c7131e76b6a1ba6ba316c90d97ffdfe184
parent14cf0b6e2f96bad1dd9ce4cc5d6fd5d0d1cae20a

Auto merge of #157320 - JonathanBrouwer:rollup-ECUZfbo, r=JonathanBrouwer

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> {
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
4694struct ConditionError {
4695 span: Span,
4696 label: String,
4697 kind: ConditionErrorKind,
4698}
4699
4700impl ConditionError {
4701 fn new(span: Span, kind: ConditionErrorKind, label: String) -> Self {
4702 Self { span, label, kind }
4703 }
4704}
4705
4706#[derive(Clone, Copy)]
4707enum ConditionErrorKind {
4708 ConditionValue,
4709 Other,
4710}
4711
4712impl ConditionErrorKind {
4713 fn describes_condition_value(self) -> bool {
4714 matches!(self, Self::ConditionValue)
4715 }
46844716}
46854717
46864718impl<'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,8 +4746,9 @@ 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",
......@@ -4721,8 +4756,9 @@ impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
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+57-18
......@@ -10,10 +10,10 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
1010use thin_vec::{ThinVec, thin_vec};
1111
1212use 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,7 +160,7 @@ 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,
......@@ -165,7 +168,7 @@ fn eii_(
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
......@@ -173,6 +176,49 @@ fn eii_(
173176 module_items.into_iter().map(Annotatable::Item).collect()
174177}
175178
179fn 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+9
......@@ -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")]
1191pub(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")]
11911200pub(crate) struct NamedArgumentUsedPositionally {
compiler/rustc_middle/src/ty/layout.rs+36-4
......@@ -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+6
......@@ -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 }
compiler/rustc_type_ir/src/infer_ctxt.rs+1
......@@ -63,6 +63,7 @@ impl TypingModeErasedStatus for MayBeErased {}
6363 feature = "nightly",
6464 derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext)
6565)]
66#[cfg_attr(feature = "nightly", rustc_must_match_exhaustively)]
6667pub enum TypingMode<I: Interner, S: TypingModeErasedStatus = MayBeErased> {
6768 /// When checking whether impls overlap, we check whether any obligations
6869 /// 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:
2222 and copy non-`rmake.rs` input support files over to `rmake_out/`. The support library is made available as an [*extern prelude*][extern_prelude].
23233. Finally, we run the recipe binary and set `rmake_out/` as the working directory.
2424
25## External dependencies
26
27`compiletest` passes tool paths and target-specific flags to `rmake.rs` through
28environment variables. Prefer using the helpers in [`run_make_support`] over
29reading these variables directly. The helpers keep command construction
30consistent across hosts and targets, and avoid relying on whichever tools happen
31to be first in `PATH`.
32
33Commonly 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
51Some of these variables are only set when the configured builder can provide the
52corresponding tool. Tests that require optional tools or LLVM target components
53should declare the matching compiletest directive, such as
54`//@ needs-force-clang-based-tests` or `//@ needs-llvm-components: x86`, instead
55of 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
57coding the lookup in individual tests.
58
2559[`run_make_support`]: ../../src/tools/run-make-support
2660[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 | }
1010 | - an `else` arm might be missing here, initializing `y`
1111LL | y
1212 | ^ `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
1315
1416error: aborting due to 1 previous error
1517
tests/ui/borrowck/borrowck-if-no-else.stderr+2
......@@ -8,6 +8,8 @@ LL | let x: isize; if 1 > 2 { x = 10; }
88 | binding declared here but left uninitialized
99LL | foo(x);
1010 | ^ `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
1113
1214error: aborting due to 1 previous error
1315
tests/ui/borrowck/borrowck-if-with-else.stderr+2
......@@ -8,6 +8,8 @@ LL | if 1 > 2 {
88...
99LL | foo(x);
1010 | ^ `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
1113
1214error: aborting due to 1 previous error
1315
tests/ui/borrowck/borrowck-while-break.stderr+2
......@@ -8,6 +8,8 @@ LL | while cond {
88...
99LL | println!("{}", v);
1010 | ^ `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
1113
1214error: aborting due to 1 previous error
1315
tests/ui/borrowck/borrowck-while.stderr+2
......@@ -7,6 +7,8 @@ LL | while 1 == 1 { x = 10; }
77 | ------ if this condition isn't met and the `while` loop runs 0 times, `x` is not initialized
88LL | return x;
99 | ^ `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
1012
1113error: aborting due to 1 previous error
1214
tests/ui/borrowck/branch-condition-flow-issue-156494.rs created+55
......@@ -0,0 +1,55 @@
1//@ edition: 2024
2
3fn 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
43fn 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 @@
1error[E0381]: used binding `following_token` isn't initialized
2 --> $DIR/branch-condition-flow-issue-156494.rs:27:21
3 |
4LL | let mut following_token: i32;
5 | ------------------- binding declared here but left uninitialized
6...
7LL | _ => {
8 | - if this pattern is matched, `following_token` is not initialized
9...
10LL | } else {
11 | ------ if the `if` condition is `false` and this `else` arm is executed, `following_token` is not initialized
12...
13LL | 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
17help: consider assigning a value
18 |
19LL | let mut following_token: i32 = 42;
20 | ++++
21
22error[E0381]: used binding `y` is possibly-uninitialized
23 --> $DIR/branch-condition-flow-issue-156494.rs:54:14
24 |
25LL | let y;
26 | - binding declared here but left uninitialized
27...
28LL | _ if condition => {}
29 | -------------- if this pattern and condition are matched, `y` is not initialized
30...
31LL | 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
36error: aborting due to 2 previous errors
37
38For 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]
12fn 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
18fn explicit_impl() {}
19fn main() {
20 example()
21 //~^ ERROR use of deprecated function
22}
tests/ui/eii/attrs.stderr created+32
......@@ -0,0 +1,32 @@
1error: only a small subset of attributes are supported on externally implementable items
2 --> $DIR/attrs.rs:12:1
3 |
4LL | fn example() {}
5 | ^^^^^^^^^^^^
6 |
7note: this attribute is not supported
8 --> $DIR/attrs.rs:5:1
9 |
10LL | #[macro_export]
11 | ^^^^^^^^^^^^^^^
12
13error: use of deprecated macro `example`: foo
14 --> $DIR/attrs.rs:16:3
15 |
16LL | #[example]
17 | ^^^^^^^
18 |
19note: the lint level is defined here
20 --> $DIR/attrs.rs:2:9
21 |
22LL | #![deny(deprecated)]
23 | ^^^^^^^^^^
24
25error: use of deprecated function `example`: foo
26 --> $DIR/attrs.rs:20:5
27 |
28LL | example()
29 | ^^^^^^^
30
31error: 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
11fn implementation();
tests/ui/eii/ice_contract_attr_on_eii_generated_item.stderr deleted-14
......@@ -1,14 +0,0 @@
1error: contract annotations is only supported in functions with bodies
2 --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
3 |
4LL | #[core::contracts::ensures]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6
7error: contract annotations can only be used on functions
8 --> $DIR/ice_contract_attr_on_eii_generated_item.rs:8:1
9 |
10LL | #[core::contracts::ensures]
11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
12
13error: 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
6use std::ptr::NonNull;
7pub 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
11fn 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> {
4848 //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
4949}
5050
51#[repr(align(16))]
52struct OverAlignWrap<T>(T);
53
54fn 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)]
61enum NotANewtype<T> {
62 SingleVariant(T),
63}
64
65fn 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)]
73enum NotNullPointerOptimized<T> {
74 Some(T),
75 None
76}
77
78fn 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
5183fn main() {}
tests/ui/transmute/transmute-different-sizes.stderr+28-1
......@@ -43,6 +43,33 @@ LL | std::mem::transmute(from)
4343 = note: source type: `*mut T` (pointer to `T`)
4444 = note: target type: `PtrAndEmptyArray<T>` (size can vary because of <T as Pointee>::Metadata)
4545
46error: aborting due to 5 previous errors
46error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
47 --> $DIR/transmute-different-sizes.rs:55:14
48 |
49LL | 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
55error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
56 --> $DIR/transmute-different-sizes.rs:66:14
57 |
58LL | 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
64error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
65 --> $DIR/transmute-different-sizes.rs:79:14
66 |
67LL | 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
73error: aborting due to 8 previous errors
4774
4875For more information about this error, try `rustc --explain E0512`.
tests/ui/transmute/transmute-fat-pointers.rs+35-2
......@@ -5,6 +5,7 @@
55#![allow(dead_code)]
66
77use std::mem::transmute;
8use std::ptr::NonNull;
89
910fn a<T, U: ?Sized>(x: &[T]) -> &U {
1011 unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes
......@@ -15,11 +16,11 @@ fn b<T: ?Sized, U: ?Sized>(x: &T) -> &U {
1516}
1617
1718fn c<T, U>(x: &T) -> &U {
18 unsafe { transmute(x) }
19 unsafe { transmute(x) } // Ok!
1920}
2021
2122fn d<T, U>(x: &[T]) -> &[U] {
22 unsafe { transmute(x) }
23 unsafe { transmute(x) } // Ok!
2324}
2425
2526fn e<T: ?Sized, U>(x: &T) -> &U {
......@@ -30,4 +31,36 @@ fn f<T, U: ?Sized>(x: &T) -> &U {
3031 unsafe { transmute(x) } //~ ERROR cannot transmute between types of different sizes
3132}
3233
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.
36fn g1<T: ?Sized>(x: &T) -> Option<&T> {
37 unsafe { transmute(x) } // Ok!
38}
39
40fn g2<T: ?Sized>(x: Option<NonNull<T>>) -> NonNull<T> {
41 unsafe { transmute(x) } // Ok!
42}
43
44fn 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`.
49fn h<T: ?Sized>(x: Box<T>) -> &'static T {
50 unsafe { transmute(x) } // Ok!
51}
52
53// Make sure we can see through newtype wrappers.
54struct Wrapper1<T>(T);
55
56#[repr(C)]
57struct Wrapper2<T>(T);
58
59fn i1<T: ?Sized>(x: &T) -> Wrapper1<&T> {
60 unsafe { transmute(x) } // Ok!
61}
62fn i2<T: ?Sized>(x: &T) -> Wrapper2<&T> {
63 unsafe { transmute(x) } // Ok!
64}
65
3366fn main() { }
tests/ui/transmute/transmute-fat-pointers.stderr+4-4
......@@ -1,5 +1,5 @@
11error[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
33 |
44LL | unsafe { transmute(x) }
55 | ^^^^^^^^^
......@@ -8,7 +8,7 @@ LL | unsafe { transmute(x) }
88 = note: target type: `&U` (pointer to `U`)
99
1010error[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
1212 |
1313LL | unsafe { transmute(x) }
1414 | ^^^^^^^^^
......@@ -17,7 +17,7 @@ LL | unsafe { transmute(x) }
1717 = note: target type: `&U` (pointer to `U`)
1818
1919error[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
2121 |
2222LL | unsafe { transmute(x) }
2323 | ^^^^^^^^^
......@@ -26,7 +26,7 @@ LL | unsafe { transmute(x) }
2626 = note: target type: `&U` (N bits)
2727
2828error[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
3030 |
3131LL | unsafe { transmute(x) }
3232 | ^^^^^^^^^
tests/ui/uninhabited/unreachable.rs+10
......@@ -4,6 +4,8 @@
44//@ check-pass
55#![deny(unreachable_code)]
66
7use std::process::ExitCode;
8
79enum Never {}
810
911fn make_never() -> Never {
......@@ -28,6 +30,14 @@ fn branchy() {
2830 }
2931}
3032
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.
36fn required_return_value() -> ExitCode {
37 make_never();
38 ExitCode::FAILURE
39}
40
3141fn main() {
3242 func();
3343 block();