summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_mir_build
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_build')
-rw-r--r--compiler/rustc_mir_build/Cargo.toml1
-rw-r--r--compiler/rustc_mir_build/messages.ftl476
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs108
-rw-r--r--compiler/rustc_mir_build/src/build/expr/category.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs61
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs85
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs45
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs41
-rw-r--r--compiler/rustc_mir_build/src/errors.rs11
-rw-r--r--compiler/rustc_mir_build/src/lib.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/block.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs15
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs25
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs119
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs71
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs17
28 files changed, 624 insertions, 534 deletions
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index f24b165d7..58449ee9e 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -14,6 +14,7 @@ rustc_apfloat = { path = "../rustc_apfloat" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" }
rustc_errors = { path = "../rustc_errors" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_infer = { path = "../rustc_infer" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index f346cd483..cb265cf2c 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -1,62 +1,40 @@
-mir_build_unconditional_recursion = function cannot return without recursing
- .label = cannot return without recursing
- .help = a `loop` may express intention better if this is on purpose
-
-mir_build_unconditional_recursion_call_site_label = recursive call site
-
-mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
- call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
- .note = consult the function's documentation for information on how to avoid undefined behavior
- .label = call to unsafe function
-
-mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
- call to unsafe function is unsafe and requires unsafe block (error E0133)
- .note = consult the function's documentation for information on how to avoid undefined behavior
- .label = call to unsafe function
-
-mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
- use of inline assembly is unsafe and requires unsafe block (error E0133)
- .note = inline assembly is entirely unchecked and can cause undefined behavior
- .label = use of inline assembly
+mir_build_adt_defined_here = `{$ty}` defined here
-mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
- initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
- block (error E0133)
- .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
- .label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
-mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
- use of mutable static is unsafe and requires unsafe block (error E0133)
- .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
- .label = use of mutable static
+mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
-mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
- use of extern static is unsafe and requires unsafe block (error E0133)
- .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
- .label = use of extern static
+mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
-mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
- dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
- .label = dereference of raw pointer
+mir_build_bindings_with_variant_name =
+ pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
+ .suggestion = to match on the variant, qualify the path
-mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
- access to union field is unsafe and requires unsafe block (error E0133)
- .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
- .label = access to union field
+mir_build_borrow = value is borrowed by `{$name}` here
-mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
- mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
- .note = mutating layout constrained fields cannot statically be checked for valid values
- .label = mutation of layout constrained field
+mir_build_borrow_of_layout_constrained_field_requires_unsafe =
+ borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
+ .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+ .label = borrow of layout constrained field with interior mutability
-mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
- borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
.note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
.label = borrow of layout constrained field with interior mutability
-mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
- call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+mir_build_borrow_of_moved_value = borrow of moved value
+ .label = value moved into `{$name}` here
+ .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+ .value_borrowed_label = value borrowed here after move
+ .suggestion = borrow this binding in the pattern to avoid moving the value
+
+mir_build_call_to_fn_with_requires_unsafe =
+ call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
+ .note = can only be called if the required target features are available
+ .label = call to function with `#[target_feature]`
+
+mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
.note = can only be called if the required target features are available
.label = call to function with `#[target_feature]`
@@ -70,55 +48,24 @@ mir_build_call_to_unsafe_fn_requires_unsafe_nameless =
.note = consult the function's documentation for information on how to avoid undefined behavior
.label = call to unsafe function
-mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- call to unsafe function `{$function}` is unsafe and requires unsafe function or block
- .note = consult the function's documentation for information on how to avoid undefined behavior
- .label = call to unsafe function
-
mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed =
call to unsafe function is unsafe and requires unsafe function or block
.note = consult the function's documentation for information on how to avoid undefined behavior
.label = call to unsafe function
-mir_build_inline_assembly_requires_unsafe =
- use of inline assembly is unsafe and requires unsafe block
- .note = inline assembly is entirely unchecked and can cause undefined behavior
- .label = use of inline assembly
-
-mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- use of inline assembly is unsafe and requires unsafe function or block
- .note = inline assembly is entirely unchecked and can cause undefined behavior
- .label = use of inline assembly
-
-mir_build_initializing_type_with_requires_unsafe =
- initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
- .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
- .label = initializing type with `rustc_layout_scalar_valid_range` attr
-
-mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
- .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
- .label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ call to unsafe function `{$function}` is unsafe and requires unsafe function or block
+ .note = consult the function's documentation for information on how to avoid undefined behavior
+ .label = call to unsafe function
-mir_build_mutable_static_requires_unsafe =
- use of mutable static is unsafe and requires unsafe block
- .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
- .label = use of mutable static
+mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
-mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- use of mutable static is unsafe and requires unsafe function or block
- .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
- .label = use of mutable static
+mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
-mir_build_extern_static_requires_unsafe =
- use of extern static is unsafe and requires unsafe block
- .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
- .label = use of extern static
+mir_build_const_pattern_depends_on_generic_parameter =
+ constant pattern depends on a generic parameter
-mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- use of extern static is unsafe and requires unsafe function or block
- .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
- .label = use of extern static
+mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
mir_build_deref_raw_pointer_requires_unsafe =
dereference of raw pointer is unsafe and requires unsafe block
@@ -130,117 +77,46 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
.note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
.label = dereference of raw pointer
-mir_build_union_field_requires_unsafe =
- access to union field is unsafe and requires unsafe block
- .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
- .label = access to union field
-
-mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- access to union field is unsafe and requires unsafe function or block
- .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
- .label = access to union field
-
-mir_build_mutation_of_layout_constrained_field_requires_unsafe =
- mutation of layout constrained field is unsafe and requires unsafe block
- .note = mutating layout constrained fields cannot statically be checked for valid values
- .label = mutation of layout constrained field
-
-mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- mutation of layout constrained field is unsafe and requires unsafe function or block
- .note = mutating layout constrained fields cannot statically be checked for valid values
- .label = mutation of layout constrained field
-
-mir_build_borrow_of_layout_constrained_field_requires_unsafe =
- borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
- .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
- .label = borrow of layout constrained field with interior mutability
-
-mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
- .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
- .label = borrow of layout constrained field with interior mutability
-
-mir_build_call_to_fn_with_requires_unsafe =
- call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
- .note = can only be called if the required target features are available
- .label = call to function with `#[target_feature]`
-
-mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
- .note = can only be called if the required target features are available
- .label = call to function with `#[target_feature]`
-
-mir_build_unused_unsafe = unnecessary `unsafe` block
- .label = unnecessary `unsafe` block
-
-mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
-mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
-
-mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
- .def_note = `{$peeled_ty}` defined here
- .type_note = the matched value is of type `{$ty}`
- .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
- .reference_note = references are always considered inhabited
- .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
- .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
-
-mir_build_static_in_pattern = statics cannot be referenced in patterns
-
-mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
-
-mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
+mir_build_extern_static_requires_unsafe =
+ use of extern static is unsafe and requires unsafe block
+ .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ .label = use of extern static
-mir_build_non_const_path = runtime values cannot be referenced in patterns
+mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ use of extern static is unsafe and requires unsafe function or block
+ .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ .label = use of extern static
-mir_build_unreachable_pattern = unreachable pattern
- .label = unreachable pattern
- .catchall_label = matches any value
+mir_build_float_pattern = floating-point types cannot be used in patterns
-mir_build_const_pattern_depends_on_generic_parameter =
- constant pattern depends on a generic parameter
+mir_build_indirect_structural_match =
+ to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
-mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
+mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
- lower range bound must be less than or equal to upper
- .label = lower bound larger than upper bound
- .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
+mir_build_initializing_type_with_requires_unsafe =
+ initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
+ .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+ .label = initializing type with `rustc_layout_scalar_valid_range` attr
-mir_build_literal_in_range_out_of_bounds =
- literal out of range for `{$ty}`
- .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
+mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+ .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+ .label = initializing type with `rustc_layout_scalar_valid_range` attr
-mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
+mir_build_inline_assembly_requires_unsafe =
+ use of inline assembly is unsafe and requires unsafe block
+ .note = inline assembly is entirely unchecked and can cause undefined behavior
+ .label = use of inline assembly
-mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
- [one] pattern
- *[other] patterns
- } in let chain
- .note = {$count ->
- [one] this pattern
- *[other] these patterns
- } will always match
- .help = consider moving {$count ->
- [one] it
- *[other] them
- } outside of the construct
+mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ use of inline assembly is unsafe and requires unsafe function or block
+ .note = inline assembly is entirely unchecked and can cause undefined behavior
+ .label = use of inline assembly
-mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
- [one] pattern
- *[other] patterns
- } in let chain
- .note = {$count ->
- [one] this pattern
- *[other] these patterns
- } will always match
- .help = consider moving {$count ->
- [one] it
- *[other] them
- } into the body
+mir_build_interpreted_as_const = introduce a variable instead
-mir_build_bindings_with_variant_name =
- pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
- .suggestion = to match on the variant, qualify the path
+mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
[one] pattern
@@ -282,78 +158,97 @@ mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count -
} will always match, so the loop will never exit
.help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
-mir_build_borrow_of_moved_value = borrow of moved value
- .label = value moved into `{$name}` here
- .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
- .value_borrowed_label = value borrowed here after move
- .suggestion = borrow this binding in the pattern to avoid moving the value
+mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
+ [one] pattern
+ *[other] patterns
+ } in let chain
+ .note = {$count ->
+ [one] this pattern
+ *[other] these patterns
+ } will always match
+ .help = consider moving {$count ->
+ [one] it
+ *[other] them
+ } outside of the construct
-mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
+mir_build_literal_in_range_out_of_bounds =
+ literal out of range for `{$ty}`
+ .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
-mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
+mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
+ lower range bound must be less than or equal to upper
+ .label = lower bound larger than upper bound
+ .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
-mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
+mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
-mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
+mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
+mir_build_moved = value is moved into `{$name}` here
-mir_build_borrow = value is borrowed by `{$name}` here
+mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
-mir_build_moved = value is moved into `{$name}` here
+mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
-mir_build_union_pattern = cannot use unions in constant patterns
+mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
-mir_build_type_not_structural =
- to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_mutable_static_requires_unsafe =
+ use of mutable static is unsafe and requires unsafe block
+ .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+ .label = use of mutable static
-mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
+mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ use of mutable static is unsafe and requires unsafe function or block
+ .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+ .label = use of mutable static
-mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
+mir_build_mutation_of_layout_constrained_field_requires_unsafe =
+ mutation of layout constrained field is unsafe and requires unsafe block
+ .note = mutating layout constrained fields cannot statically be checked for valid values
+ .label = mutation of layout constrained field
-mir_build_float_pattern = floating-point types cannot be used in patterns
+mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ mutation of layout constrained field is unsafe and requires unsafe function or block
+ .note = mutating layout constrained fields cannot statically be checked for valid values
+ .label = mutation of layout constrained field
-mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+mir_build_non_const_path = runtime values cannot be referenced in patterns
-mir_build_indirect_structural_match =
- to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
+ .help = ensure that all variants are matched explicitly by adding the suggested match arms
+ .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
+
+mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
+ .def_note = `{$peeled_ty}` defined here
+ .type_note = the matched value is of type `{$ty}`
+ .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
+ .reference_note = references are always considered inhabited
+ .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
mir_build_nontrivial_structural_match =
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
-mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
-
-mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
.range = ... with this range
.note = you likely meant to write mutually exclusive ranges
-mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
- .help = ensure that all variants are matched explicitly by adding the suggested match arms
- .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
-
-mir_build_uncovered = {$count ->
- [1] pattern `{$witness_1}`
- [2] patterns `{$witness_1}` and `{$witness_2}`
- [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
- *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
- } not covered
-
mir_build_pattern_not_covered = refutable pattern in {$origin}
.pattern_ty = the matched value is of type `{$pattern_ty}`
-mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
-mir_build_adt_defined_here = `{$ty}` defined here
+mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
+ .attributes = no other attributes may be applied
+ .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
+ .missing_box = `#[rustc_box]` requires the `owned_box` lang item
-mir_build_variant_defined_here = not covered
+mir_build_static_in_pattern = statics cannot be referenced in patterns
-mir_build_interpreted_as_const = introduce a variable instead
+mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
-mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
[one] variant that isn't
@@ -365,10 +260,117 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
*[other] variants that aren't
} matched
-mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
+ [one] pattern
+ *[other] patterns
+ } in let chain
+ .note = {$count ->
+ [one] this pattern
+ *[other] these patterns
+ } will always match
+ .help = consider moving {$count ->
+ [one] it
+ *[other] them
+ } into the body
+
+mir_build_type_not_structural =
+ to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
- .attributes = no other attributes may be applied
- .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
- .missing_box = `#[rustc_box]` requires the `owned_box` lang item
+mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
+
+mir_build_unconditional_recursion = function cannot return without recursing
+ .label = cannot return without recursing
+ .help = a `loop` may express intention better if this is on purpose
+
+mir_build_unconditional_recursion_call_site_label = recursive call site
+
+mir_build_uncovered = {$count ->
+ [1] pattern `{$witness_1}`
+ [2] patterns `{$witness_1}` and `{$witness_2}`
+ [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
+ *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
+ } not covered
+
+mir_build_union_field_requires_unsafe =
+ access to union field is unsafe and requires unsafe block
+ .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+ .label = access to union field
+
+mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ access to union field is unsafe and requires unsafe function or block
+ .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+ .label = access to union field
+
+mir_build_union_pattern = cannot use unions in constant patterns
+
+mir_build_unreachable_pattern = unreachable pattern
+ .label = unreachable pattern
+ .catchall_label = matches any value
+
+mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
+ borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+ .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+ .label = borrow of layout constrained field with interior mutability
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
+ call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+ .note = can only be called if the required target features are available
+ .label = call to function with `#[target_feature]`
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
+ call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
+ .note = consult the function's documentation for information on how to avoid undefined behavior
+ .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
+ call to unsafe function is unsafe and requires unsafe block (error E0133)
+ .note = consult the function's documentation for information on how to avoid undefined behavior
+ .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
+ dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ .label = dereference of raw pointer
+
+mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
+ use of extern static is unsafe and requires unsafe block (error E0133)
+ .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ .label = use of extern static
+
+mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
+ initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
+ block (error E0133)
+ .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+ .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
+ use of inline assembly is unsafe and requires unsafe block (error E0133)
+ .note = inline assembly is entirely unchecked and can cause undefined behavior
+ .label = use of inline assembly
+
+mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
+ use of mutable static is unsafe and requires unsafe block (error E0133)
+ .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+ .label = use of mutable static
+
+mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
+ mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
+ .note = mutating layout constrained fields cannot statically be checked for valid values
+ .label = mutation of layout constrained field
+
+mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
+ access to union field is unsafe and requires unsafe block (error E0133)
+ .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+ .label = access to union field
+
+mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
+
+mir_build_unused_unsafe = unnecessary `unsafe` block
+ .label = unnecessary `unsafe` block
+
+mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
+mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
+
+mir_build_variant_defined_here = not covered
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 609ab1928..ab4cd2488 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -351,7 +351,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
let popped = this.block_context.pop();
- assert!(popped.map_or(false, |bf| bf.is_statement()));
+ assert!(popped.is_some_and(|bf| bf.is_statement()));
}
// Then, the block may have an optional trailing expression which is a “return” value
@@ -367,7 +367,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
unpack!(block = this.expr_into_dest(destination, block, expr));
let popped = this.block_context.pop();
- assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
+ assert!(popped.is_some_and(|bf| bf.is_tail_expr()));
} else {
// If a block has no trailing expression, then it is given an implicit return type.
// This return type is usually `()`, unless the block is diverging, in which case the
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index d385153ba..32c618828 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -21,7 +21,7 @@ use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::{
mir::*,
thir::*,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index 12b2f5d80..803207d9d 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -1,4 +1,4 @@
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_middle::{mir::*, thir::*, ty::Ty};
use rustc_span::Span;
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 931fe1b24..ebf830cb9 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -57,6 +57,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
place: self.parse_place(args[0])?,
target: self.parse_block(args[1])?,
unwind: UnwindAction::Continue,
+ replace: false,
})
},
@call("mir_call", args) => {
@@ -154,6 +155,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
},
@call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
+ @call("mir_copy_for_deref", args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
ExprKind::Borrow { borrow_kind, arg } => Ok(
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
),
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 99291740a..4d99ab4b0 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -52,7 +52,7 @@ pub fn as_constant_inner<'tcx>(
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
Ok(c) => c,
Err(LitToConstError::Reported(guar)) => {
- ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
+ ConstantKind::Ty(tcx.const_error(ty, guar))
}
Err(LitToConstError::TypeError) => {
bug!("encountered type error in `lit_to_mir_constant`")
@@ -78,7 +78,7 @@ pub fn as_constant_inner<'tcx>(
ExprKind::NamedConst { def_id, substs, ref user_ty } => {
let user_ty = user_ty.as_ref().and_then(push_cuta);
- let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval = mir::UnevaluatedConst::new(def_id, substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty, span, literal }
@@ -90,7 +90,7 @@ pub fn as_constant_inner<'tcx>(
Constant { user_ty: None, span, literal }
}
ExprKind::ConstBlock { did: def_id, substs } => {
- let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval = mir::UnevaluatedConst::new(def_id, substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty: None, span, literal }
@@ -146,6 +146,12 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
}
+ (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
+ {
+ let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
+ let allocation = tcx.mk_const_alloc(allocation);
+ ConstValue::Slice { data: allocation, start: 0, end: data.len() }
+ }
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 6941da331..744111edb 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -118,7 +118,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let category = Category::of(&expr.kind).unwrap();
debug!(?category, ?expr.kind);
match category {
- Category::Constant if let NeedsTemporary::No = needs_temporary || !expr.ty.needs_drop(this.tcx, this.param_env) => {
+ Category::Constant
+ if matches!(needs_temporary, NeedsTemporary::No)
+ || !expr.ty.needs_drop(this.tcx, this.param_env) =>
+ {
let constant = this.as_constant(expr);
block.and(Operand::Constant(Box::new(constant)))
}
@@ -126,7 +129,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
// Overwrite temp local info if we have something more interesting to record.
if !matches!(local_info, LocalInfo::Boring) {
- let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local();
+ let decl_info =
+ this.local_decls[operand].local_info.as_mut().assert_crate_local();
if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info {
**decl_info = local_info;
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index fb775766c..7ec57add6 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -557,6 +557,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. }
+ | ExprKind::OffsetOf { .. }
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. } => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 8631749a5..3742d640e 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -1,6 +1,6 @@
//! See docs in `build/expr/mod.rs`.
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::ty::util::IntTypeExt;
use rustc_target::abi::{Abi, FieldIdx, Primitive};
@@ -15,6 +15,7 @@ use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
+use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
@@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
let (op,ty) = (Operand::Move(discr), discr_ty);
- if let Abi::Scalar(scalar) = layout.unwrap().abi{
- if let Primitive::Int(_, signed) = scalar.primitive() {
- let range = scalar.valid_range(&this.tcx);
- // FIXME: Handle wraparound cases too.
- if range.end >= range.start {
- let mut assumer = |range: u128, bin_op: BinOp| {
- // We will be overwriting this val if our scalar is signed value
- // because sign extension on unsigned types might cause unintended things
- let mut range_val =
- ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
- let bool_ty = this.tcx.types.bool;
- if signed {
- let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
- let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
- let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
- range_val = ConstantKind::from_bits(
- this.tcx,
- truncated_val,
- ty::ParamEnv::empty().and(discr_ty),
- );
- }
- let lit_op = this.literal_operand(expr.span, range_val);
- let is_bin_op = this.temp(bool_ty, expr_span);
- this.cfg.push_assign(
- block,
- source_info,
- is_bin_op,
- Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
- );
- this.cfg.push(
- block,
- Statement {
- source_info,
- kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
- Operand::Copy(is_bin_op),
- ))),
- },
- )
- };
- assumer(range.end, BinOp::Ge);
- assumer(range.start, BinOp::Le);
- }
- }
+ if let Abi::Scalar(scalar) = layout.unwrap().abi
+ && !scalar.is_always_valid(&this.tcx)
+ && let Primitive::Int(int_width, _signed) = scalar.primitive()
+ {
+ let unsigned_ty = int_width.to_ty(this.tcx, false);
+ let unsigned_place = this.temp(unsigned_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ unsigned_place,
+ Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty));
+
+ let bool_ty = this.tcx.types.bool;
+ let range = scalar.valid_range(&this.tcx);
+ let merge_op =
+ if range.start <= range.end {
+ BinOp::BitAnd
+ } else {
+ BinOp::BitOr
+ };
+
+ let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
+ let range_val =
+ ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
+ let lit_op = this.literal_operand(expr.span, range_val);
+ let is_bin_op = this.temp(bool_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ is_bin_op,
+ Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))),
+ );
+ is_bin_op
+ };
+ let assert_place = if range.start == 0 {
+ comparer(range.end, BinOp::Le)
+ } else {
+ let start_place = comparer(range.start, BinOp::Ge);
+ let end_place = comparer(range.end, BinOp::Le);
+ let merge_place = this.temp(bool_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ merge_place,
+ Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))),
+ );
+ merge_place
+ };
+ this.cfg.push(
+ block,
+ Statement {
+ source_info,
+ kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
+ Operand::Move(assert_place),
+ ))),
+ },
+ );
}
(op,ty)
@@ -481,6 +496,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}))))
}
+ ExprKind::OffsetOf { container, fields } => {
+ block.and(Rvalue::NullaryOp(NullOp::OffsetOf(fields), container))
+ }
+
ExprKind::Literal { .. }
| ExprKind::NamedConst { .. }
| ExprKind::NonHirLiteral { .. }
@@ -706,6 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: to_drop,
target: success,
unwind: UnwindAction::Continue,
+ replace: false,
},
);
this.diverge_from(block);
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index d33401f07..d9aa461c1 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -67,7 +67,8 @@ impl Category {
| ExprKind::Repeat { .. }
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
- | ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
+ | ExprKind::ThreadLocalRef(_)
+ | ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
ExprKind::ConstBlock { .. }
| ExprKind::Literal { .. }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 05a723a6b..29ff916d2 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -163,13 +163,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
//
// [block: If(lhs)] -true-> [else_block: dest = (rhs)]
// | (false)
- // [shortcurcuit_block: dest = false]
+ // [shortcircuit_block: dest = false]
//
// Or:
//
// [block: If(lhs)] -false-> [else_block: dest = (rhs)]
// | (true)
- // [shortcurcuit_block: dest = true]
+ // [shortcircuit_block: dest = true]
let (shortcircuit_block, mut else_block, join_block) = (
this.cfg.start_new_block(),
@@ -561,7 +561,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ZstLiteral { .. }
| ExprKind::ConstParam { .. }
| ExprKind::ThreadLocalRef(_)
- | ExprKind::StaticRef { .. } => {
+ | ExprKind::StaticRef { .. }
+ | ExprKind::OffsetOf { .. } => {
debug_assert!(match Category::of(&expr.kind).unwrap() {
// should be handled above
Category::Rvalue(RvalueFunc::Into) => false,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 4926ff85d..6df06df5c 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -2241,6 +2241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
+ references: 0,
value: VarDebugInfoContents::Place(for_arm_body.into()),
argument_index: None,
});
@@ -2260,6 +2261,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
+ references: 0,
value: VarDebugInfoContents::Place(ref_for_guard.into()),
argument_index: None,
});
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 8a03ea7e2..dbdb5b4a9 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -77,7 +77,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| PatKind::Wild
| PatKind::Binding { .. }
| PatKind::Leaf { .. }
- | PatKind::Deref { .. } => self.error_simplifyable(match_pair),
+ | PatKind::Deref { .. } => self.error_simplifiable(match_pair),
}
}
@@ -173,7 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug_assert_ne!(
target_blocks[idx.index()],
otherwise_block,
- "no canididates for tested discriminant: {:?}",
+ "no candidates for tested discriminant: {:?}",
discr,
);
Some((discr.val, target_blocks[idx.index()]))
@@ -181,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug_assert_eq!(
target_blocks[idx.index()],
otherwise_block,
- "found canididates for untested discriminant: {:?}",
+ "found candidates for untested discriminant: {:?}",
discr,
);
None
@@ -380,18 +380,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
}
- /// Compare two `&T` values using `<T as std::compare::PartialEq>::eq`
+ /// Compare two values using `<T as std::compare::PartialEq>::eq`.
+ /// If the values are already references, just call it directly, otherwise
+ /// take a reference to the values first and then call it.
fn non_scalar_compare(
&mut self,
block: BasicBlock,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
source_info: SourceInfo,
value: ConstantKind<'tcx>,
- place: Place<'tcx>,
+ mut val: Place<'tcx>,
mut ty: Ty<'tcx>,
) {
let mut expect = self.literal_operand(source_info.span, value);
- let mut val = Operand::Copy(place);
// If we're using `b"..."` as a pattern, we need to insert an
// unsizing coercion, as the byte string has the type `&[u8; N]`.
@@ -421,9 +422,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
source_info,
temp,
- Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty),
+ Rvalue::Cast(
+ CastKind::Pointer(PointerCast::Unsize),
+ Operand::Copy(val),
+ ty,
+ ),
);
- val = Operand::Move(temp);
+ val = temp;
}
if opt_ref_test_ty.is_some() {
let slice = self.temp(ty, source_info.span);
@@ -438,12 +443,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
- let ty::Ref(_, deref_ty, _) = *ty.kind() else {
- bug!("non_scalar_compare called on non-reference type: {}", ty);
- };
+ match *ty.kind() {
+ ty::Ref(_, deref_ty, _) => ty = deref_ty,
+ _ => {
+ // non_scalar_compare called on non-reference type
+ let temp = self.temp(ty, source_info.span);
+ self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect));
+ let ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, ty);
+ let ref_temp = self.temp(ref_ty, source_info.span);
+
+ self.cfg.push_assign(
+ block,
+ source_info,
+ ref_temp,
+ Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, temp),
+ );
+ expect = Operand::Move(ref_temp);
+
+ let ref_temp = self.temp(ref_ty, source_info.span);
+ self.cfg.push_assign(
+ block,
+ source_info,
+ ref_temp,
+ Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val),
+ );
+ val = ref_temp;
+ }
+ }
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
- let method = trait_method(self.tcx, eq_def_id, sym::eq, [deref_ty, deref_ty]);
+ let method = trait_method(self.tcx, eq_def_id, sym::eq, [ty, ty]);
let bool_ty = self.tcx.types.bool;
let eq_result = self.temp(bool_ty, source_info.span);
@@ -463,7 +492,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
literal: method,
})),
- args: vec![val, expect],
+ args: vec![Operand::Copy(val), expect],
destination: eq_result,
target: Some(eq_block),
unwind: UnwindAction::Continue,
@@ -499,7 +528,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// However, in some cases, the test may just not be relevant to candidate.
/// For example, suppose we are testing whether `foo.x == 22`, but in one
/// match arm we have `Foo { x: _, ... }`... in that case, the test for
- /// what value `x` has has no particular relevance to this candidate. In
+ /// the value of `x` has no particular relevance to this candidate. In
/// such cases, this function just returns None without doing anything.
/// This is used by the overall `match_candidates` algorithm to structure
/// the match as a whole. See `match_candidates` for more details.
@@ -763,8 +792,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate.match_pairs.extend(consequent_match_pairs);
}
- fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
- span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
+ fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
+ span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
}
fn const_range_contains(
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index bc50bcbc3..4e3e98b56 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -11,7 +11,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{GeneratorKind, Node};
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::middle::region;
@@ -32,43 +32,34 @@ use super::lints;
pub(crate) fn mir_built(
tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
) -> &rustc_data_structures::steal::Steal<Body<'_>> {
- if let Some(def) = def.try_upgrade(tcx) {
- return tcx.mir_built(def);
- }
-
- let mut body = mir_build(tcx, def);
- if def.const_param_did.is_some() {
- assert!(matches!(body.source.instance, ty::InstanceDef::Item(_)));
- body.source = MirSource::from_instance(ty::InstanceDef::Item(def.to_global()));
- }
-
- tcx.alloc_steal_mir(body)
+ tcx.alloc_steal_mir(mir_build(tcx, def))
}
/// Construct the MIR for a given `DefId`.
-fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
// Ensure unsafeck and abstract const building is ran before we steal the THIR.
- match def {
- ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
- tcx.ensure_with_value().thir_check_unsafety_for_const_arg((did, const_param_did));
- tcx.ensure_with_value().thir_abstract_const_of_const_arg((did, const_param_did));
- }
- ty::WithOptConstParam { did, const_param_did: None } => {
- tcx.ensure_with_value().thir_check_unsafety(did);
- tcx.ensure_with_value().thir_abstract_const(did);
- tcx.ensure_with_value().check_match(did);
- }
+ tcx.ensure_with_value().thir_check_unsafety(def);
+ tcx.ensure_with_value().thir_abstract_const(def);
+ if let Err(e) = tcx.check_match(def) {
+ return construct_error(tcx, def, e);
}
let body = match tcx.thir_body(def) {
- Err(error_reported) => construct_error(tcx, def.did, error_reported),
+ Err(error_reported) => construct_error(tcx, def, error_reported),
Ok((thir, expr)) => {
// We ran all queries that depended on THIR at the beginning
// of `mir_build`, so now we can steal it
let thir = thir.steal();
+ tcx.ensure().check_match(def);
+ // this must run before MIR dump, because
+ // "not all control paths return a value" is reported here.
+ //
+ // maybe move the check to a MIR pass?
+ tcx.ensure().check_liveness(def);
+
match thir.body_type {
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig),
thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty),
@@ -161,8 +152,7 @@ struct Builder<'a, 'tcx> {
thir: &'a Thir<'tcx>,
cfg: CFG<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
- def_id: DefId,
+ def_id: LocalDefId,
hir_id: hir::HirId,
parent_module: DefId,
check_overflow: bool,
@@ -428,26 +418,26 @@ macro_rules! unpack {
fn construct_fn<'tcx>(
tcx: TyCtxt<'tcx>,
- fn_def: ty::WithOptConstParam<LocalDefId>,
+ fn_def: LocalDefId,
thir: &Thir<'tcx>,
expr: ExprId,
fn_sig: ty::FnSig<'tcx>,
) -> Body<'tcx> {
- let span = tcx.def_span(fn_def.did);
- let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did);
- let generator_kind = tcx.generator_kind(fn_def.did);
+ let span = tcx.def_span(fn_def);
+ let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def);
+ let generator_kind = tcx.generator_kind(fn_def);
// The representation of thir for `-Zunpretty=thir-tree` relies on
// the entry expression being the last element of `thir.exprs`.
assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
// Figure out what primary body this item has.
- let body_id = tcx.hir().body_owned_by(fn_def.did);
+ let body_id = tcx.hir().body_owned_by(fn_def);
let span_with_body = tcx.hir().span_with_body(fn_id);
let return_ty_span = tcx
.hir()
.fn_decl_by_hir_id(fn_id)
- .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def.did))
+ .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def))
.output
.span();
@@ -457,7 +447,7 @@ fn construct_fn<'tcx>(
};
let mut abi = fn_sig.abi;
- if let DefKind::Closure = tcx.def_kind(fn_def.did) {
+ if let DefKind::Closure = tcx.def_kind(fn_def) {
// HACK(eddyb) Avoid having RustCall on closures,
// as it adds unnecessary (and wrong) auto-tupling.
abi = Abi::Rust;
@@ -483,7 +473,7 @@ fn construct_fn<'tcx>(
{
return custom::build_custom_mir(
tcx,
- fn_def.did.to_def_id(),
+ fn_def.to_def_id(),
fn_id,
thir,
expr,
@@ -547,12 +537,12 @@ fn construct_fn<'tcx>(
fn construct_const<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
thir: &'a Thir<'tcx>,
expr: ExprId,
const_ty: Ty<'tcx>,
) -> Body<'tcx> {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def);
// Figure out what primary body this item has.
let (span, const_ty_span) = match tcx.hir().get(hir_id) {
@@ -568,10 +558,10 @@ fn construct_const<'a, 'tcx>(
..
}) => (*span, ty.span),
Node::AnonConst(_) => {
- let span = tcx.def_span(def.did);
+ let span = tcx.def_span(def);
(span, span)
}
- _ => span_bug!(tcx.def_span(def.did), "can't build MIR for {:?}", def.did),
+ _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
};
let infcx = tcx.infer_ctxt().build();
@@ -669,7 +659,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn new(
thir: &'a Thir<'tcx>,
infcx: InferCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
hir_id: hir::HirId,
span: Span,
arg_count: usize,
@@ -688,20 +678,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
check_overflow |= tcx.sess.overflow_checks();
// Constants always need overflow checks.
check_overflow |= matches!(
- tcx.hir().body_owner_kind(def.did),
+ tcx.hir().body_owner_kind(def),
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
);
let lint_level = LintLevel::Explicit(hir_id);
- let param_env = tcx.param_env(def.did);
+ let param_env = tcx.param_env(def);
let mut builder = Builder {
thir,
tcx,
infcx,
- region_scope_tree: tcx.region_scope_tree(def.did),
+ region_scope_tree: tcx.region_scope_tree(def),
param_env,
- def,
- def_id: def.did.to_def_id(),
+ def_id: def,
hir_id,
parent_module: tcx.parent_module(hir_id).to_def_id(),
check_overflow,
@@ -741,7 +730,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
Body::new(
- MirSource::item(self.def_id),
+ MirSource::item(self.def_id.to_def_id()),
self.cfg.basic_blocks,
self.source_scopes,
self.local_decls,
@@ -779,7 +768,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let tcx = self.tcx;
self.upvars = tcx
- .closure_captures(self.def.did)
+ .closure_captures(self.def_id)
.iter()
.zip(capture_tys)
.enumerate()
@@ -809,6 +798,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
};
self.var_debug_info.push(VarDebugInfo {
name,
+ references: 0,
source_info: SourceInfo::outermost(captured_place.var_ident.span),
value: VarDebugInfoContents::Place(use_place),
argument_index: None,
@@ -839,6 +829,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info,
+ references: 0,
value: VarDebugInfoContents::Place(arg_local.into()),
argument_index: Some(argument_index as u16 + 1),
});
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index f32d2db4e..7c0fbc6f8 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -86,12 +86,12 @@ use std::mem;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::HirId;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{Expr, LintLevel};
-use rustc_span::{DesugaringKind, Span, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
#[derive(Debug)]
pub struct Scopes<'tcx> {
@@ -325,10 +325,10 @@ impl DropTree {
entry_points.sort();
for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
- if entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
+ if entry_points.last().is_some_and(|entry_point| entry_point.0 == drop_idx) {
let block = *blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
needs_block[drop_idx] = Block::Own;
- while entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
+ while entry_points.last().is_some_and(|entry_point| entry_point.0 == drop_idx) {
let entry_block = entry_points.pop().unwrap().1;
T::add_entry(cfg, entry_block, block);
}
@@ -371,6 +371,7 @@ impl DropTree {
// The caller will handle this if needed.
unwind: UnwindAction::Terminate,
place: drop_data.0.local.into(),
+ replace: false,
};
cfg.terminate(block, drop_data.0.source_info, terminator);
}
@@ -644,24 +645,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
};
- if let Some(destination) = destination {
- if let Some(value) = value {
+ match (destination, value) {
+ (Some(destination), Some(value)) => {
debug!("stmt_expr Break val block_context.push(SubExpr)");
self.block_context.push(BlockFrame::SubExpr);
unpack!(block = self.expr_into_dest(destination, block, value));
self.block_context.pop();
- } else {
+ }
+ (Some(destination), None) => {
self.cfg.push_assign_unit(block, source_info, destination, self.tcx)
}
- } else {
- assert!(value.is_none(), "`return` and `break` should have a destination");
- if self.tcx.sess.instrument_coverage() {
+ (None, Some(_)) => {
+ panic!("`return`, `become` and `break` with value and must have a destination")
+ }
+ (None, None) if self.tcx.sess.instrument_coverage() => {
// Unlike `break` and `return`, which push an `Assign` statement to MIR, from which
// a Coverage code region can be generated, `continue` needs no `Assign`; but
// without one, the `InstrumentCoverage` MIR pass cannot generate a code region for
// `continue`. Coverage will be missing unless we add a dummy `Assign` to MIR.
self.add_dummy_assignment(span, block, source_info);
}
+ (None, None) => {}
}
let region_scope = self.scopes.breakable_scopes[break_index].region_scope;
@@ -671,12 +675,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
self.scopes.breakable_scopes[break_index].continue_drops.as_mut().unwrap()
};
- let mut drop_idx = ROOT_NODE;
- for scope in &self.scopes.scopes[scope_index + 1..] {
- for drop in &scope.drops {
- drop_idx = drops.add_drop(*drop, drop_idx);
- }
- }
+
+ let drop_idx = self.scopes.scopes[scope_index + 1..]
+ .iter()
+ .flat_map(|scope| &scope.drops)
+ .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx));
+
drops.add_entry(block, drop_idx);
// `build_drop_trees` doesn't have access to our source_info, so we
@@ -728,7 +732,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
// If we are emitting a `drop` statement, we need to have the cached
// diverge cleanup pads ready in case that drop panics.
- let needs_cleanup = self.scopes.scopes.last().map_or(false, |scope| scope.needs_cleanup());
+ let needs_cleanup = self.scopes.scopes.last().is_some_and(|scope| scope.needs_cleanup());
let is_generator = self.generator_kind.is_some();
let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX };
@@ -1125,9 +1129,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: Place<'tcx>,
value: Rvalue<'tcx>,
) -> BlockAnd<()> {
- let span = self.tcx.with_stable_hashing_context(|hcx| {
- span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx)
- });
let source_info = self.source_info(span);
// create the new block for the assignment
@@ -1145,6 +1146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place,
target: assign,
unwind: UnwindAction::Cleanup(assign_unwind),
+ replace: true,
},
);
self.diverge_from(block);
@@ -1172,7 +1174,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Assert {
cond,
expected,
- msg,
+ msg: Box::new(msg),
target: success_block,
unwind: UnwindAction::Continue,
},
@@ -1258,6 +1260,7 @@ fn build_scope_drops<'tcx>(
place: local.into(),
target: next,
unwind: UnwindAction::Continue,
+ replace: false,
},
);
block = next;
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 03a7f2d70..0506f2bf2 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -117,10 +117,10 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
}
/// Handle closures/generators/inline-consts, which is unsafecked with their parent body.
- fn visit_inner_body(&mut self, def: ty::WithOptConstParam<LocalDefId>) {
+ fn visit_inner_body(&mut self, def: LocalDefId) {
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
let inner_thir = &inner_thir.borrow();
- let hir_context = self.tcx.hir().local_def_id_to_hir_id(def.did);
+ let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
inner_visitor.visit_expr(&inner_thir[expr]);
// Unsafe blocks can be used in the inner body, make sure to take it into account
@@ -323,6 +323,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::Box { .. }
| ExprKind::If { .. }
| ExprKind::InlineAsm { .. }
+ | ExprKind::OffsetOf { .. }
| ExprKind::LogicalOp { .. }
| ExprKind::Use { .. } => {
// We don't need to save the old value and restore it
@@ -396,18 +397,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
movability: _,
fake_reads: _,
}) => {
- let closure_def = if let Some((did, const_param_id)) =
- ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
- {
- ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
- } else {
- ty::WithOptConstParam::unknown(closure_id)
- };
- self.visit_inner_body(closure_def);
+ self.visit_inner_body(closure_id);
}
ExprKind::ConstBlock { did, substs: _ } => {
let def_id = did.expect_local();
- self.visit_inner_body(ty::WithOptConstParam::unknown(def_id));
+ self.visit_inner_body(def_id);
}
ExprKind::Field { lhs, .. } => {
let lhs = &self.thir[lhs];
@@ -706,14 +700,14 @@ impl UnsafeOpKind {
}
}
-pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
+pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
// THIR unsafeck is gated under `-Z thir-unsafeck`
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
return;
}
// Closures and inline consts are handled by their owner, if it has a body
- if tcx.is_typeck_child(def.did.to_def_id()) {
+ if tcx.is_typeck_child(def.to_def_id()) {
return;
}
@@ -726,7 +720,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
return;
}
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def);
let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
BodyUnsafety::Unsafe(fn_sig.span)
@@ -734,7 +728,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
BodyUnsafety::Safe
}
});
- let body_target_features = &tcx.body_codegen_attrs(def.did.to_def_id()).target_features;
+ let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let mut visitor = UnsafetyVisitor {
@@ -746,23 +740,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
body_target_features,
assignment_info: None,
in_union_destructure: false,
- param_env: tcx.param_env(def.did),
+ param_env: tcx.param_env(def),
inside_adt: false,
};
visitor.visit_expr(&thir[expr]);
}
-
-pub(crate) fn thir_check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
- tcx.thir_check_unsafety_for_const_arg(def)
- } else {
- check_unsafety(tcx, ty::WithOptConstParam::unknown(def_id))
- }
-}
-
-pub(crate) fn thir_check_unsafety_for_const_arg(
- tcx: TyCtxt<'_>,
- (did, param_did): (LocalDefId, DefId),
-) {
- check_unsafety(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
-}
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 43e787db4..7c0df201b 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -384,13 +384,8 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
diag.span_note(span, fluent::mir_build_def_note);
}
- let is_variant_list_non_exhaustive = match self.ty.kind() {
- ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => {
- true
- }
- _ => false,
- };
-
+ let is_variant_list_non_exhaustive = matches!(self.ty.kind(),
+ ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
if is_variant_list_non_exhaustive {
diag.note(fluent::mir_build_non_exhaustive_type_note);
} else {
@@ -786,6 +781,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
pub interpreted_as_const: Option<InterpretedAsConst>,
#[subdiagnostic]
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
+ #[note(mir_build_privately_uninhabited)]
+ pub witness_1_is_privately_uninhabited: Option<()>,
#[note(mir_build_pattern_ty)]
pub _p: (),
pub pattern_ty: Ty<'tcx>,
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 3f9236c9d..c964e62c9 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -22,10 +22,10 @@ mod errors;
mod lints;
pub mod thir;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
fluent_messages! { "../messages.ftl" }
@@ -35,7 +35,6 @@ pub fn provide(providers: &mut Providers) {
providers.lit_to_mir_constant = build::lit_to_mir_constant;
providers.mir_built = build::mir_built;
providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
- providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
providers.thir_body = thir::cx::thir_body;
providers.thir_tree = thir::print::thir_tree;
providers.thir_flat = thir::print::thir_flat;
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 8aacec53f..a46ad6423 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -5,7 +5,7 @@ use rustc_middle::middle::region;
use rustc_middle::thir::*;
use rustc_middle::ty;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'tcx> Cx<'tcx> {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 8e2e92e6f..b20495d60 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -5,7 +5,7 @@ use crate::thir::util::UserAnnotatedTyHelpers;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
@@ -130,6 +130,7 @@ impl<'tcx> Cx<'tcx> {
ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) }
}
Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) },
+ Adjust::NeverToAny if adjustment.target.is_never() => return expr,
Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
Adjust::Deref(None) => {
adjust_span(&mut expr);
@@ -332,7 +333,7 @@ impl<'tcx> Cx<'tcx> {
} else if let Some(box_item) = tcx.lang_items().owned_box() {
if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = fun.kind
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
- && path.res.opt_def_id().map_or(false, |did| did == box_item)
+ && path.res.opt_def_id().is_some_and(|did| did == box_item)
&& fn_path.ident.name == sym::new
&& let [value] = args
{
@@ -664,6 +665,14 @@ impl<'tcx> Cx<'tcx> {
line_spans: asm.line_spans,
})),
+ hir::ExprKind::OffsetOf(_, _) => {
+ let data = self.typeck_results.offset_of_data();
+ let &(container, ref indices) = data.get(expr.hir_id).unwrap();
+ let fields = tcx.mk_fields_from_iter(indices.iter().copied());
+
+ ExprKind::OffsetOf { container, fields }
+ }
+
hir::ExprKind::ConstBlock(ref anon_const) => {
let ty = self.typeck_results().node_type(anon_const.hir_id);
let did = anon_const.def_id.to_def_id();
@@ -947,7 +956,7 @@ impl<'tcx> Cx<'tcx> {
let is_upvar = self
.tcx
.upvars_mentioned(self.body_owner)
- .map_or(false, |upvars| upvars.contains_key(&var_hir_id));
+ .is_some_and(|upvars| upvars.contains_key(&var_hir_id));
debug!(
"convert_var({:?}): is_upvar={}, body_owner={:?}",
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 070544446..463f639de 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -20,25 +20,25 @@ use rustc_span::Span;
pub(crate) fn thir_body(
tcx: TyCtxt<'_>,
- owner_def: ty::WithOptConstParam<LocalDefId>,
+ owner_def: LocalDefId,
) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
let hir = tcx.hir();
- let body = hir.body(hir.body_owned_by(owner_def.did));
+ let body = hir.body(hir.body_owned_by(owner_def));
let mut cx = Cx::new(tcx, owner_def);
if let Some(reported) = cx.typeck_results.tainted_by_errors {
return Err(reported);
}
let expr = cx.mirror_expr(&body.value);
- let owner_id = hir.local_def_id_to_hir_id(owner_def.did);
+ let owner_id = hir.local_def_id_to_hir_id(owner_def);
if let Some(ref fn_decl) = hir.fn_decl_by_hir_id(owner_id) {
- let closure_env_param = cx.closure_env_param(owner_def.did, owner_id);
+ let closure_env_param = cx.closure_env_param(owner_def, owner_id);
let explicit_params = cx.explicit_params(owner_id, fn_decl, body);
cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect();
// The resume argument may be missing, in that case we need to provide it here.
// It will always be `()` in this case.
- if tcx.def_kind(owner_def.did) == DefKind::Generator && body.params.is_empty() {
+ if tcx.def_kind(owner_def) == DefKind::Generator && body.params.is_empty() {
cx.thir.params.push(Param {
ty: tcx.mk_unit(),
pat: None,
@@ -78,13 +78,12 @@ struct Cx<'tcx> {
}
impl<'tcx> Cx<'tcx> {
- fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
- let typeck_results = tcx.typeck_opt_const_arg(def);
- let did = def.did;
+ fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Cx<'tcx> {
+ let typeck_results = tcx.typeck(def);
let hir = tcx.hir();
- let hir_id = hir.local_def_id_to_hir_id(did);
+ let hir_id = hir.local_def_id_to_hir_id(def);
- let body_type = if hir.body_owner_kind(did).is_fn_or_closure() {
+ let body_type = if hir.body_owner_kind(def).is_fn_or_closure() {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
@@ -106,11 +105,11 @@ impl<'tcx> Cx<'tcx> {
Cx {
tcx,
thir: Thir::new(body_type),
- param_env: tcx.param_env(def.did),
- region_scope_tree: tcx.region_scope_tree(def.did),
+ param_env: tcx.param_env(def),
+ region_scope_tree: tcx.region_scope_tree(def),
typeck_results,
rvalue_scopes: &typeck_results.rvalue_scopes,
- body_owner: did.to_def_id(),
+ body_owner: def.to_def_id(),
adjustment_span: None,
apply_adjustments: hir
.attrs(hir_id)
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 8f58db504..1e51cb9aa 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -26,8 +26,8 @@ use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::Span;
-pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let Ok((thir, expr)) = tcx.thir_body(ty::WithOptConstParam::unknown(def_id)) else { return };
+pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
+ let (thir, expr) = tcx.thir_body(def_id)?;
let thir = thir.borrow();
let pattern_arena = TypedArena::default();
let mut visitor = MatchVisitor {
@@ -37,13 +37,16 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) {
lint_level: tcx.hir().local_def_id_to_hir_id(def_id),
let_source: LetSource::None,
pattern_arena: &pattern_arena,
+ error: Ok(()),
};
visitor.visit_expr(&thir[expr]);
+
for param in thir.params.iter() {
if let Some(box ref pattern) = param.pat {
visitor.check_irrefutable(pattern, "function argument", None);
}
}
+ visitor.error
}
fn create_e0004(
@@ -77,6 +80,7 @@ struct MatchVisitor<'a, 'p, 'tcx> {
lint_level: HirId,
let_source: LetSource,
pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
+ error: Result<(), ErrorGuaranteed>,
}
impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
@@ -86,35 +90,34 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
#[instrument(level = "trace", skip(self))]
fn visit_arm(&mut self, arm: &Arm<'tcx>) {
- match arm.guard {
- Some(Guard::If(expr)) => {
- self.with_let_source(LetSource::IfLetGuard, |this| {
- this.visit_expr(&this.thir[expr])
- });
- }
- Some(Guard::IfLet(ref pat, expr)) => {
- self.with_let_source(LetSource::IfLetGuard, |this| {
- this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
- this.visit_pat(pat);
- this.visit_expr(&this.thir[expr]);
- });
+ self.with_lint_level(arm.lint_level, |this| {
+ match arm.guard {
+ Some(Guard::If(expr)) => {
+ this.with_let_source(LetSource::IfLetGuard, |this| {
+ this.visit_expr(&this.thir[expr])
+ });
+ }
+ Some(Guard::IfLet(ref pat, expr)) => {
+ this.with_let_source(LetSource::IfLetGuard, |this| {
+ this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
+ this.visit_pat(pat);
+ this.visit_expr(&this.thir[expr]);
+ });
+ }
+ None => {}
}
- None => {}
- }
- self.visit_pat(&arm.pattern);
- self.visit_expr(&self.thir[arm.body]);
+ this.visit_pat(&arm.pattern);
+ this.visit_expr(&self.thir[arm.body]);
+ });
}
#[instrument(level = "trace", skip(self))]
fn visit_expr(&mut self, ex: &Expr<'tcx>) {
match ex.kind {
ExprKind::Scope { value, lint_level, .. } => {
- let old_lint_level = self.lint_level;
- if let LintLevel::Explicit(hir_id) = lint_level {
- self.lint_level = hir_id;
- }
- self.visit_expr(&self.thir[value]);
- self.lint_level = old_lint_level;
+ self.with_lint_level(lint_level, |this| {
+ this.visit_expr(&this.thir[value]);
+ });
return;
}
ExprKind::If { cond, then, else_opt, if_then_scope: _ } => {
@@ -186,6 +189,17 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
self.let_source = old_let_source;
}
+ fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) {
+ if let LintLevel::Explicit(hir_id) = new_lint_level {
+ let old_lint_level = self.lint_level;
+ self.lint_level = hir_id;
+ f(self);
+ self.lint_level = old_lint_level;
+ } else {
+ f(self);
+ }
+ }
+
fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
check_for_bindings_named_same_as_variants(self, pat, rf);
@@ -232,7 +246,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
for &arm in arms {
// Check the arm for some things unrelated to exhaustiveness.
let arm = &self.thir.arms[arm];
- self.check_patterns(&arm.pattern, Refutable);
+ self.with_lint_level(arm.lint_level, |this| {
+ this.check_patterns(&arm.pattern, Refutable);
+ });
}
let tarms: Vec<_> = arms
@@ -276,9 +292,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let [pat_field] = &subpatterns[..] else { bug!() };
self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None);
} else {
- non_exhaustive_match(
+ self.error = Err(non_exhaustive_match(
&cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
- );
+ ));
}
}
}
@@ -406,7 +422,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
}
#[instrument(level = "trace", skip(self))]
- fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
+ fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
let mut cx = self.new_cx(self.lint_level, false);
let pattern = self.lower_pattern(&mut cx, pat);
@@ -475,18 +491,36 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
AdtDefinedHere { adt_def_span, ty, variants }
};
- self.tcx.sess.emit_err(PatternNotCovered {
+ // Emit an extra note if the first uncovered witness would be uninhabited
+ // if we disregard visibility.
+ let witness_1_is_privately_uninhabited =
+ if cx.tcx.features().exhaustive_patterns
+ && let Some(witness_1) = witnesses.get(0)
+ && let ty::Adt(adt, substs) = witness_1.ty().kind()
+ && adt.is_enum()
+ && let Constructor::Variant(variant_index) = witness_1.ctor()
+ {
+ let variant = adt.variant(*variant_index);
+ let inhabited = variant.inhabited_predicate(cx.tcx, *adt).subst(cx.tcx, substs);
+ assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module));
+ !inhabited.apply_ignore_module(cx.tcx, cx.param_env)
+ } else {
+ false
+ };
+
+ self.error = Err(self.tcx.sess.emit_err(PatternNotCovered {
span: pat.span,
origin,
uncovered: Uncovered::new(pat.span, &cx, witnesses),
inform,
interpreted_as_const,
+ witness_1_is_privately_uninhabited: witness_1_is_privately_uninhabited.then_some(()),
_p: (),
pattern_ty,
let_suggestion,
misc_suggestion,
adt_defined_here,
- });
+ }));
}
}
@@ -628,7 +662,7 @@ fn non_exhaustive_match<'p, 'tcx>(
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
arms: &[ArmId],
expr_span: Span,
-) {
+) -> ErrorGuaranteed {
let is_empty_match = arms.is_empty();
let non_empty_enum = match scrut_ty.kind() {
ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
@@ -640,13 +674,12 @@ fn non_exhaustive_match<'p, 'tcx>(
let pattern;
let patterns_len;
if is_empty_match && !non_empty_enum {
- cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
+ return cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
cx,
expr_span,
span: sp,
ty: scrut_ty,
});
- return;
} else {
// FIXME: migration of this diagnostic will require list support
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
@@ -668,13 +701,11 @@ fn non_exhaustive_match<'p, 'tcx>(
};
};
- let is_variant_list_non_exhaustive = match scrut_ty.kind() {
- ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => true,
- _ => false,
- };
+ let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(),
+ ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
- err.note(&format!(
+ err.note(format!(
"the matched value is of type `{}`{}",
scrut_ty,
if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
@@ -684,13 +715,13 @@ fn non_exhaustive_match<'p, 'tcx>(
&& witnesses.len() == 1
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
{
- err.note(&format!(
+ err.note(format!(
"`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
exhaustively",
scrut_ty,
));
if cx.tcx.sess.is_nightly_build() {
- err.help(&format!(
+ err.help(format!(
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
enable precise `{}` matching",
scrut_ty,
@@ -795,11 +826,11 @@ fn non_exhaustive_match<'p, 'tcx>(
},
);
if let Some((span, sugg)) = suggestion {
- err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
} else {
- err.help(&msg);
+ err.help(msg);
}
- err.emit();
+ err.emit()
}
pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
@@ -859,7 +890,7 @@ fn adt_defined_here<'p, 'tcx>(
for pat in spans {
span.push_span_label(pat, "not covered");
}
- err.span_note(span, &format!("`{}` defined here", ty));
+ err.span_note(span, format!("`{}` defined here", ty));
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 32d0404bd..b243f1dc8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,5 +1,5 @@
use rustc_hir as hir;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::mir;
@@ -62,21 +62,13 @@ struct ConstToPat<'tcx> {
treat_byte_string_as_slice: bool,
}
-mod fallback_to_const_ref {
- #[derive(Debug)]
- /// This error type signals that we encountered a non-struct-eq situation behind a reference.
- /// We bubble this up in order to get back to the reference destructuring and make that emit
- /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
- /// on such patterns (since that function takes a reference) and not have to jump through any
- /// hoops to get a reference to the value.
- pub(super) struct FallbackToConstRef(());
-
- pub(super) fn fallback_to_const_ref(c2p: &super::ConstToPat<'_>) -> FallbackToConstRef {
- assert!(c2p.behind_reference.get());
- FallbackToConstRef(())
- }
-}
-use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef};
+/// This error type signals that we encountered a non-struct-eq situation.
+/// We bubble this up in order to get back to the reference destructuring and make that emit
+/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
+/// on such patterns (since that function takes a reference) and not have to jump through any
+/// hoops to get a reference to the value.
+#[derive(Debug)]
+struct FallbackToConstRef;
impl<'tcx> ConstToPat<'tcx> {
fn new(
@@ -156,7 +148,7 @@ impl<'tcx> ConstToPat<'tcx> {
if let Some(non_sm_ty) = structural {
if !self.type_may_have_partial_eq_impl(cv.ty()) {
- // fatal avoids ICE from resolution of non-existent method (rare case).
+ // fatal avoids ICE from resolution of nonexistent method (rare case).
self.tcx()
.sess
.emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty });
@@ -191,7 +183,7 @@ impl<'tcx> ConstToPat<'tcx> {
self.tcx(),
ObligationCause::dummy(),
self.param_env,
- self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]),
+ ty::TraitRef::new(self.tcx(), partial_eq_trait_id, [ty, ty]),
);
// FIXME: should this call a `predicate_must_hold` variant instead?
@@ -236,13 +228,13 @@ impl<'tcx> ConstToPat<'tcx> {
let kind = match cv.ty().kind() {
ty::Float(_) => {
- tcx.emit_spanned_lint(
- lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
- id,
- span,
- FloatPattern,
- );
- PatKind::Constant { value: cv }
+ tcx.emit_spanned_lint(
+ lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+ id,
+ span,
+ FloatPattern,
+ );
+ return Err(FallbackToConstRef);
}
ty::Adt(adt_def, _) if adt_def.is_union() => {
// Matching on union fields is unsafe, we can't hide it in constants
@@ -289,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> {
// Since we are behind a reference, we can just bubble the error up so we get a
// constant at reference type, making it easy to let the fallback call
// `PartialEq::eq` on it.
- return Err(fallback_to_const_ref(self));
+ return Err(FallbackToConstRef);
}
ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
debug!(
@@ -393,11 +385,11 @@ impl<'tcx> ConstToPat<'tcx> {
self.behind_reference.set(old);
val
}
- // Backwards compatibility hack: support references to non-structural types.
- // We'll lower
- // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
- // reference. This makes the rest of the matching logic simpler as it doesn't have
- // to figure out how to get a reference again.
+ // Backwards compatibility hack: support references to non-structural types,
+ // but hard error if we aren't behind a double reference. We could just use
+ // the fallback code path below, but that would allow *more* of this fishy
+ // code to compile, as then it only goes through the future incompat lint
+ // instead of a hard error.
ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
if self.behind_reference.get() {
if !self.saw_const_match_error.get()
@@ -411,7 +403,7 @@ impl<'tcx> ConstToPat<'tcx> {
IndirectStructuralMatch { non_sm_ty: *pointee_ty },
);
}
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
} else {
if !self.saw_const_match_error.get() {
self.saw_const_match_error.set(true);
@@ -435,16 +427,9 @@ impl<'tcx> ConstToPat<'tcx> {
PatKind::Wild
} else {
let old = self.behind_reference.replace(true);
- // In case there are structural-match violations somewhere in this subpattern,
- // we fall back to a const pattern. If we do not do this, we may end up with
- // a !structural-match constant that is not of reference type, which makes it
- // very hard to invoke `PartialEq::eq` on it as a fallback.
- let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) {
- Ok(subpattern) => PatKind::Deref { subpattern },
- Err(_) => PatKind::Constant { value: cv },
- };
+ let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?;
self.behind_reference.set(old);
- val
+ PatKind::Deref { subpattern }
}
}
},
@@ -452,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> {
PatKind::Constant { value: cv }
}
ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
}
// FIXME: these can have very surprising behaviour where optimization levels or other
// compilation choices change the runtime behaviour of the match.
@@ -469,7 +454,7 @@ impl<'tcx> ConstToPat<'tcx> {
PointerPattern
);
}
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
}
_ => {
self.saw_const_match_error.set(true);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 7c2919644..6a7714613 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,7 +52,7 @@ use smallvec::{smallvec, SmallVec};
use rustc_data_structures::captures::Captures;
use rustc_hir::{HirId, RangeEnd};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
@@ -844,8 +844,8 @@ impl<'tcx> Constructor<'tcx> {
}
/// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
- /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
- /// assumed to have been split from a wildcard.
+ /// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out,
+ /// and `self` is assumed to have been split from a wildcard.
fn is_covered_by_any<'p>(
&self,
pcx: &PatCtxt<'_, 'p, 'tcx>,
@@ -894,7 +894,7 @@ impl<'tcx> Constructor<'tcx> {
/// in `to_ctors`: in some cases we only return `Missing`.
#[derive(Debug)]
pub(super) struct SplitWildcard<'tcx> {
- /// Constructors seen in the matrix.
+ /// Constructors (other than wildcards and opaques) seen in the matrix.
matrix_ctors: Vec<Constructor<'tcx>>,
/// All the constructors for this type
all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
@@ -1037,7 +1037,7 @@ impl<'tcx> SplitWildcard<'tcx> {
// Since `all_ctors` never contains wildcards, this won't recurse further.
self.all_ctors =
self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
- self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
+ self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect();
}
/// Whether there are any value constructors for this type that are not present in the matrix.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 70d015a39..1cf2f7ec0 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -16,7 +16,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::RangeEnd;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::interpret::{
ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
};
@@ -229,7 +229,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr)
}
None => {
- let msg = &format!(
+ let msg = format!(
"found bad range pattern `{:?}` outside of error recovery",
(&lo, &hi),
);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index d8f66a175..e5b635069 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -288,6 +288,22 @@
//!
//! The details are not necessary to understand this file, so we explain them in
//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
+//!
+//! # Constants in patterns
+//!
+//! There are two kinds of constants in patterns:
+//!
+//! * literals (`1`, `true`, `"foo"`)
+//! * named or inline consts (`FOO`, `const { 5 + 6 }`)
+//!
+//! The latter are converted into other patterns with literals at the leaves. For example
+//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])`
+//! pattern. This gets problematic when comparing the constant via `==` would behave differently
+//! from matching on the constant converted to a pattern. Situations like that can occur, when
+//! the user implements `PartialEq` manually, and thus could make `==` behave arbitrarily different.
+//! In order to honor the `==` implementation, constants of types that implement `PartialEq` manually
+//! stay as a full constant and become an `Opaque` pattern. These `Opaque` patterns do not participate
+//! in exhaustiveness, specialization or overlap checking.
use self::ArmType::*;
use self::Usefulness::*;
@@ -685,10 +701,9 @@ enum ArmType {
/// For example, if we are constructing a witness for the match against
///
/// ```compile_fail,E0004
-/// # #![feature(type_ascription)]
/// struct Pair(Option<(u32, u32)>, bool);
/// # fn foo(p: Pair) {
-/// match (p: Pair) {
+/// match p {
/// Pair(None, _) => {}
/// Pair(_, false) => {}
/// }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index ed61d6ee7..b2f2a64e2 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::LocalDefId;
use std::fmt::{self, Write};
-pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
match super::cx::thir_body(tcx, owner_def) {
Ok((thir, _)) => {
let thir = thir.steal();
@@ -15,7 +15,7 @@ pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalD
}
}
-pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
match super::cx::thir_body(tcx, owner_def) {
Ok((thir, _)) => format!("{:#?}", thir.steal()),
Err(_) => "error".into(),
@@ -519,6 +519,19 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_inline_asm_expr(&**expr, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
+ OffsetOf { container, fields } => {
+ print_indented!(self, "OffsetOf {", depth_lvl);
+ print_indented!(self, format!("container: {:?}", container), depth_lvl + 1);
+ print_indented!(self, "fields: [", depth_lvl + 1);
+
+ for field in fields.iter() {
+ print_indented!(self, format!("{:?}", field), depth_lvl + 2);
+ print_indented!(self, ",", depth_lvl + 1);
+ }
+
+ print_indented!(self, "]", depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
ThreadLocalRef(def_id) => {
print_indented!(self, "ThreadLocalRef {", depth_lvl);
print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);