From dd01f75a8901200ce9e4daaef97f34d33551cf2e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 20 Apr 2024 14:53:14 +0200 Subject: [PATCH 1/7] Move duplicated code in functions in `tests/rustdoc-gui/notable-trait.goml` --- tests/rustdoc-gui/notable-trait.goml | 208 ++++++++++++--------------- 1 file changed, 89 insertions(+), 119 deletions(-) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 34fafe9a1412..6ee810c5768c 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -2,47 +2,70 @@ include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" show-text: true -// We start with a wide screen. -set-window-size: (1100, 600) -// Checking they have the same y position. -compare-elements-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["y"], -) -// Checking they don't have the same x position. -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["x"], -) -// The `i` should be *after* the type. -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - {"x": 677}, -) -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - {"x": 955}, -) -// The tooltip should be below the `i` -// Also, clicking the tooltip should bring its text into the DOM -assert-count: ("//*[@class='tooltip popover']", 0) -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -assert-count: ("//*[@class='tooltip popover']", 1) -compare-elements-position-near: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - {"y": 30} + +define-function: ( + "check-notable-tooltip-position", + [x, i_x], + block { + // Checking they have the same y position. + compare-elements-position: ( + "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + ["y"], + ) + // Checking they don't have the same x position. + compare-elements-position-false: ( + "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + ["x"], + ) + // The `i` should be *after* the type. + assert-position: ( + "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", + {"x": |x|}, + ) + assert-position: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + {"x": |i_x|}, + ) + }, ) -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - ["x"] + +define-function: ( + "check-notable-tooltip-position-complete", + [x, i_x, popover_x], + block { + call-function: ("check-notable-tooltip-position", {"x": |x|, "i_x": |i_x|}) + assert-count: ("//*[@class='tooltip popover']", 0) + click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" + assert-count: ("//*[@class='tooltip popover']", 1) + compare-elements-position-near: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + "//*[@class='tooltip popover']", + {"y": 30} + ) + compare-elements-position-false: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + "//*[@class='tooltip popover']", + ["x"] + ) + assert-position: ( + "//*[@class='tooltip popover']", + {"x": |popover_x|} + ) + click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" + move-cursor-to: "//h1" + assert-count: ("//*[@class='tooltip popover']", 0) + }, ) -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -move-cursor-to: "//h1" -assert-count: ("//*[@class='tooltip popover']", 0) + +// We start with a wide screen. +set-window-size: (1100, 600) +call-function: ("check-notable-tooltip-position-complete", { + "x": 677, + "i_x": 955, + "popover_x": 463, +}) // Now only the `i` should be on the next line. set-window-size: (1055, 600) @@ -54,71 +77,18 @@ compare-elements-position-false: ( // Now both the `i` and the struct name should be on the next line. set-window-size: (980, 600) -// Checking they have the same y position. -compare-elements-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["y"], -) -// Checking they don't have the same x position. -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["x"], -) -// The `i` should be *after* the type. -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - {"x": 245}, -) -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - {"x": 523}, -) +call-function: ("check-notable-tooltip-position", { + "x": 245, + "i_x": 523, +}) // Checking on mobile now. set-window-size: (650, 600) -// Checking they have the same y position. -compare-elements-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["y"], -) -// Checking they don't have the same x position. -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - ["x"], -) -// The `i` should be *after* the type. -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", - {"x": 15}, -) -assert-position: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - {"x": 293}, -) -// The tooltip should STILL be below `i` -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -assert-count: ("//*[@class='tooltip popover']", 1) -compare-elements-position-near: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - {"y": 30} -) -compare-elements-position-false: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", - "//*[@class='tooltip popover']", - ["x"] -) -assert-position: ( - "//*[@class='tooltip popover']", - {"x": 0} -) -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -move-cursor-to: "//h1" -assert-count: ("//*[@class='tooltip popover']", 0) +call-function: ("check-notable-tooltip-position-complete", { + "x": 15, + "i_x": 293, + "popover_x": 0, +}) // Now check the colors. define-function: ( @@ -236,31 +206,31 @@ press-key: "Tab" assert-count: ("//*[@class='tooltip popover']", 0) assert: "#method\.create_an_iterator_from_read .tooltip:focus" +define-function: ( + "setup-popup", + [], + block { + store-window-property: {"scrollY": scroll} + click: "#method\.create_an_iterator_from_read .fn" + // We ensure that the scroll position changed. + assert-window-property-false: {"scrollY": |scroll|} + // Store the new position. + store-window-property: {"scrollY": scroll} + click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" + wait-for: "//*[@class='tooltip popover']" + click: "#settings-menu a" + } +) + // Now we check that the focus isn't given back to the wrong item when opening // another popover. -store-window-property: {"scrollY": scroll} -click: "#method\.create_an_iterator_from_read .fn" -// We ensure that the scroll position changed. -assert-window-property-false: {"scrollY": |scroll|} -// Store the new position. -store-window-property: {"scrollY": scroll} -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -wait-for: "//*[@class='tooltip popover']" -click: "#settings-menu a" +call-function: ("setup-popup", {}) click: ".search-input" // We ensure we didn't come back to the previous focused item. assert-window-property-false: {"scrollY": |scroll|} // Same but with Escape handling. -store-window-property: {"scrollY": scroll} -click: "#method\.create_an_iterator_from_read .fn" -// We ensure that the scroll position changed. -assert-window-property-false: {"scrollY": |scroll|} -// Store the new position. -store-window-property: {"scrollY": scroll} -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -wait-for: "//*[@class='tooltip popover']" -click: "#settings-menu a" +call-function: ("setup-popup", {}) press-key: "Escape" // We ensure we didn't come back to the previous focused item. assert-window-property-false: {"scrollY": |scroll|} From 875f0c2da05da9a7620afd6e2be04fbcb9a4b395 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2024 11:35:02 +0200 Subject: [PATCH 2/7] Miri: detect wrong vtables in wide pointers --- compiler/rustc_const_eval/messages.ftl | 12 +-- compiler/rustc_const_eval/src/errors.rs | 17 ++++ .../rustc_const_eval/src/interpret/cast.rs | 6 +- .../rustc_const_eval/src/interpret/place.rs | 17 +++- .../src/interpret/terminator.rs | 20 ++-- .../src/interpret/validity.rs | 23 ++++- .../rustc_const_eval/src/interpret/visitor.rs | 8 +- .../rustc_middle/src/mir/interpret/error.rs | 99 +++++++++++++++---- .../tests/fail/dyn-call-trait-mismatch.rs | 5 +- .../tests/fail/dyn-call-trait-mismatch.stderr | 4 +- .../tests/fail/dyn-upcast-nop-wrong-trait.rs | 15 +++ .../fail/dyn-upcast-nop-wrong-trait.stderr | 15 +++ .../tests/fail/dyn-upcast-trait-mismatch.rs | 9 +- .../fail/dyn-upcast-trait-mismatch.stderr | 6 +- .../fail/validity/wrong-dyn-trait-generic.rs | 12 +++ .../validity/wrong-dyn-trait-generic.stderr | 15 +++ .../tests/fail/validity/wrong-dyn-trait.rs | 6 ++ .../fail/validity/wrong-dyn-trait.stderr | 15 +++ .../tests/pass/cast-rfc0401-vtable-kinds.rs | 2 +- src/tools/miri/tests/pass/dyn-upcast.rs | 42 ++++---- tests/ui/cast/cast-rfc0401-vtable-kinds.rs | 2 +- 21 files changed, 265 insertions(+), 85 deletions(-) create mode 100644 src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs create mode 100644 src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr create mode 100644 src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.rs create mode 100644 src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr create mode 100644 src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs create mode 100644 src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f6937dc145d5..b79d7441acac 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -82,12 +82,6 @@ const_eval_double_storage_live = const_eval_dyn_call_not_a_method = `dyn` call trying to call something that is not a method -const_eval_dyn_call_vtable_mismatch = - `dyn` call on a pointer whose vtable does not match its type - -const_eval_dyn_star_call_vtable_mismatch = - `dyn*` call on a pointer whose vtable does not match its type - const_eval_error = {$error_kind -> [static] could not evaluate static initializer [const] evaluation of constant value failed @@ -192,6 +186,8 @@ const_eval_invalid_uninit_bytes_unknown = const_eval_invalid_vtable_pointer = using {$pointer} as vtable pointer but it does not point to a vtable +const_eval_invalid_vtable_trait = + using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected const_eval_live_drop = destructor of `{$dropped_ty}` cannot be evaluated at compile-time @@ -401,9 +397,6 @@ const_eval_unterminated_c_string = const_eval_unwind_past_top = unwinding past the topmost frame of the stack -const_eval_upcast_mismatch = - upcast on a pointer whose vtable does not match its type - ## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`. ## (We'd love to sort this differently to make that more clear but tidy won't let us...) const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant @@ -450,6 +443,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer +const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$ref_trait}`, but encountered `{$vtable_trait}` const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` const_eval_validation_null_box = {$front_matter}: encountered a null box diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index a60cedd6500d..90d4f1168e4f 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -498,6 +498,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { InvalidTag(_) => const_eval_invalid_tag, InvalidFunctionPointer(_) => const_eval_invalid_function_pointer, InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer, + InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait, InvalidStr(_) => const_eval_invalid_str, InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown, InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes, @@ -537,6 +538,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { | DeadLocal | UninhabitedEnumVariantWritten(_) | UninhabitedEnumVariantRead(_) => {} + BoundsCheckFailed { len, index } => { diag.arg("len", len); diag.arg("index", index); @@ -544,6 +546,13 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { diag.arg("pointer", ptr); } + InvalidVTableTrait { expected_trait, vtable_trait } => { + diag.arg("expected_trait", expected_trait.to_string()); + diag.arg( + "vtable_trait", + vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("")), + ); + } PointerUseAfterFree(alloc_id, msg) => { diag.arg("alloc_id", alloc_id) .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); @@ -634,6 +643,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant, Uninit { .. } => const_eval_validation_uninit, InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr, + InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait, InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => { const_eval_validation_invalid_box_slice_meta } @@ -773,6 +783,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { DanglingPtrNoProvenance { pointer, .. } => { err.arg("pointer", pointer); } + InvalidMetaWrongTrait { expected_trait: ref_trait, vtable_trait } => { + err.arg("ref_trait", ref_trait.to_string()); + err.arg( + "vtable_trait", + vtable_trait.map(|t| t.to_string()).unwrap_or_else(|| format!("")), + ); + } NullPtr { .. } | PtrToStatic { .. } | ConstRefToMutable diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 9447d18fe8c9..76e59ea90559 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -393,6 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = self.read_immediate(src)?; if data_a.principal() == data_b.principal() { // A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables. + // (But currently mismatching vtables violate the validity invariant so UB is triggered anyway.) return self.write_immediate(*val, dest); } let (old_data, old_vptr) = val.to_scalar_pair(); @@ -400,7 +401,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_vptr = old_vptr.to_pointer(self)?; let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; if old_trait != data_a.principal() { - throw_ub_custom!(fluent::const_eval_upcast_mismatch); + throw_ub!(InvalidVTableTrait { + expected_trait: data_a, + vtable_trait: old_trait, + }); } let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 8364a5a8d186..e5241f1ba19e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -1020,16 +1020,20 @@ where pub(super) fn unpack_dyn_trait( &self, mplace: &MPlaceTy<'tcx, M::Provenance>, + expected_trait: &'tcx ty::List>, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer>)> { assert!( matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)), "`unpack_dyn_trait` only makes sense on `dyn*` types" ); let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; - let (ty, _) = self.get_ptr_vtable(vtable)?; - let layout = self.layout_of(ty)?; + let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?; + if expected_trait.principal() != vtable_trait { + throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); + } // This is a kind of transmute, from a place with unsized type and metadata to // a place with sized type and no metadata. + let layout = self.layout_of(ty)?; let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout }; Ok((mplace, vtable)) @@ -1040,6 +1044,7 @@ where pub(super) fn unpack_dyn_star>( &self, val: &P, + expected_trait: &'tcx ty::List>, ) -> InterpResult<'tcx, (P, Pointer>)> { assert!( matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)), @@ -1048,10 +1053,12 @@ where let data = self.project_field(val, 0)?; let vtable = self.project_field(val, 1)?; let vtable = self.read_pointer(&vtable.to_op(self)?)?; - let (ty, _) = self.get_ptr_vtable(vtable)?; + let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?; + if expected_trait.principal() != vtable_trait { + throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); + } + // `data` is already the right thing but has the wrong type. So we transmute it. let layout = self.layout_of(ty)?; - // `data` is already the right thing but has the wrong type. So we transmute it, by - // projecting with offset 0. let data = data.transmute(layout, self)?; Ok((data, vtable)) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index c0e27e86d500..0c3b01d449bd 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -802,11 +802,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) = receiver_place.layout.ty.kind() { - let (recv, vptr) = self.unpack_dyn_star(&receiver_place)?; - let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; - if dyn_trait != data.principal() { - throw_ub_custom!(fluent::const_eval_dyn_star_call_vtable_mismatch); - } + let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?; + let (dyn_ty, _dyn_trait) = self.get_ptr_vtable(vptr)?; (vptr, dyn_ty, recv.ptr()) } else { @@ -828,7 +825,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; if dyn_trait != data.principal() { - throw_ub_custom!(fluent::const_eval_dyn_call_vtable_mismatch); + throw_ub!(InvalidVTableTrait { + expected_trait: data, + vtable_trait: dyn_trait, + }); } // It might be surprising that we use a pointer as the receiver even if this @@ -938,13 +938,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let place = self.force_allocation(place)?; let place = match place.layout.ty.kind() { - ty::Dynamic(_, _, ty::Dyn) => { + ty::Dynamic(data, _, ty::Dyn) => { // Dropping a trait object. Need to find actual drop fn. - self.unpack_dyn_trait(&place)?.0 + self.unpack_dyn_trait(&place, data)?.0 } - ty::Dynamic(_, _, ty::DynStar) => { + ty::Dynamic(data, _, ty::DynStar) => { // Dropping a `dyn*`. Need to find actual drop fn. - self.unpack_dyn_star(&place)?.0 + self.unpack_dyn_star(&place, data)?.0 } _ => { debug_assert_eq!( diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b8a1733e45ad..14566719ccd7 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -339,16 +339,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind() { - ty::Dynamic(_, _, ty::Dyn) => { + ty::Dynamic(data, _, ty::Dyn) => { let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; // Make sure it is a genuine vtable pointer. - let (_ty, _trait) = try_validation!( + let (_dyn_ty, dyn_trait) = try_validation!( self.ecx.get_ptr_vtable(vtable), self.path, Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) => InvalidVTablePtr { value: format!("{vtable}") } ); - // FIXME: check if the type/trait match what ty::Dynamic says? + // Make sure it is for the right trait. + if dyn_trait != data.principal() { + throw_validation_failure!( + self.path, + InvalidMetaWrongTrait { expected_trait: data, vtable_trait: dyn_trait } + ); + } } ty::Slice(..) | ty::Str => { let _len = meta.unwrap_meta().to_target_usize(self.ecx)?; @@ -933,7 +939,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } } _ => { - self.walk_value(op)?; // default handler + // default handler + try_validation!( + self.walk_value(op), + self.path, + // It's not great to catch errors here, since we can't give a very good path, + // but it's better than ICEing. + Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => { + InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait } + }, + ); } } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 0e824f3f592d..84557b8e2d60 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -88,22 +88,22 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { // Special treatment for special types, where the (static) layout is not sufficient. match *ty.kind() { // If it is a trait object, switch to the real type that was used to create it. - ty::Dynamic(_, _, ty::Dyn) => { + ty::Dynamic(data, _, ty::Dyn) => { // Dyn types. This is unsized, and the actual dynamic type of the data is given by the // vtable stored in the place metadata. // unsized values are never immediate, so we can assert_mem_place let op = v.to_op(self.ecx())?; let dest = op.assert_mem_place(); - let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.0; + let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?.0; trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); // recurse with the inner type return self.visit_field(v, 0, &inner_mplace.into()); } - ty::Dynamic(_, _, ty::DynStar) => { + ty::Dynamic(data, _, ty::DynStar) => { // DynStar types. Very different from a dyn type (but strangely part of the // same variant in `TyKind`): These are pairs where the 2nd component is the // vtable, and the first component is the data (which must be ptr-sized). - let data = self.ecx().unpack_dyn_star(v)?.0; + let data = self.ecx().unpack_dyn_star(v, data)?.0; return self.visit_field(v, 0, &data); } // Slices do not need special handling here: they have `Array` field diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 65ce1cd8f50c..a3d16d4f097a 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -2,7 +2,7 @@ use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; -use crate::ty::{layout, tls, Ty, TyCtxt, ValTree}; +use crate::ty::{self, layout, tls, Ty, TyCtxt, ValTree}; use rustc_ast_ir::Mutability; use rustc_data_structures::sync::Lock; @@ -344,6 +344,11 @@ pub enum UndefinedBehaviorInfo<'tcx> { InvalidFunctionPointer(Pointer), /// Using a pointer-not-to-a-vtable as vtable pointer. InvalidVTablePointer(Pointer), + /// Using a vtable for the wrong trait. + InvalidVTableTrait { + expected_trait: &'tcx ty::List>, + vtable_trait: Option>, + }, /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. @@ -414,34 +419,86 @@ impl From for ExpectedKind { #[derive(Debug)] pub enum ValidationErrorKind<'tcx> { - PointerAsInt { expected: ExpectedKind }, + PointerAsInt { + expected: ExpectedKind, + }, PartialPointer, - PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> }, - PtrToStatic { ptr_kind: PointerKind }, + PtrToUninhabited { + ptr_kind: PointerKind, + ty: Ty<'tcx>, + }, + PtrToStatic { + ptr_kind: PointerKind, + }, ConstRefToMutable, ConstRefToExtern, MutableRefToImmutable, UnsafeCellInImmutable, NullFnPtr, NeverVal, - NullablePtrOutOfRange { range: WrappingRange, max_value: u128 }, - PtrOutOfRange { range: WrappingRange, max_value: u128 }, - OutOfRange { value: String, range: WrappingRange, max_value: u128 }, - UninhabitedVal { ty: Ty<'tcx> }, - InvalidEnumTag { value: String }, + NullablePtrOutOfRange { + range: WrappingRange, + max_value: u128, + }, + PtrOutOfRange { + range: WrappingRange, + max_value: u128, + }, + OutOfRange { + value: String, + range: WrappingRange, + max_value: u128, + }, + UninhabitedVal { + ty: Ty<'tcx>, + }, + InvalidEnumTag { + value: String, + }, UninhabitedEnumVariant, - Uninit { expected: ExpectedKind }, - InvalidVTablePtr { value: String }, - InvalidMetaSliceTooLarge { ptr_kind: PointerKind }, - InvalidMetaTooLarge { ptr_kind: PointerKind }, - UnalignedPtr { ptr_kind: PointerKind, required_bytes: u64, found_bytes: u64 }, - NullPtr { ptr_kind: PointerKind }, - DanglingPtrNoProvenance { ptr_kind: PointerKind, pointer: String }, - DanglingPtrOutOfBounds { ptr_kind: PointerKind }, - DanglingPtrUseAfterFree { ptr_kind: PointerKind }, - InvalidBool { value: String }, - InvalidChar { value: String }, - InvalidFnPtr { value: String }, + Uninit { + expected: ExpectedKind, + }, + InvalidVTablePtr { + value: String, + }, + InvalidMetaWrongTrait { + expected_trait: &'tcx ty::List>, + vtable_trait: Option>, + }, + InvalidMetaSliceTooLarge { + ptr_kind: PointerKind, + }, + InvalidMetaTooLarge { + ptr_kind: PointerKind, + }, + UnalignedPtr { + ptr_kind: PointerKind, + required_bytes: u64, + found_bytes: u64, + }, + NullPtr { + ptr_kind: PointerKind, + }, + DanglingPtrNoProvenance { + ptr_kind: PointerKind, + pointer: String, + }, + DanglingPtrOutOfBounds { + ptr_kind: PointerKind, + }, + DanglingPtrUseAfterFree { + ptr_kind: PointerKind, + }, + InvalidBool { + value: String, + }, + InvalidChar { + value: String, + }, + InvalidFnPtr { + value: String, + }, } /// Error information for when the program did something that might (or might not) be correct diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs index 13f913454dcd..f71df9a1c909 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs @@ -1,3 +1,6 @@ +// Validation stops this too early. +//@compile-flags: -Zmiri-disable-validation + trait T1 { #[allow(dead_code)] fn method1(self: Box); @@ -13,5 +16,5 @@ impl T1 for i32 { fn main() { let r = Box::new(0) as Box; let r2: Box = unsafe { std::mem::transmute(r) }; - r2.method2(); //~ERROR: call on a pointer whose vtable does not match its type + r2.method2(); //~ERROR: using vtable for trait `T1` but trait `T2` was expected } diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr index 365186bcc4b4..019a55bcdcb1 100644 --- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr +++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: `dyn` call on a pointer whose vtable does not match its type +error: Undefined Behavior: using vtable for trait `T1` but trait `T2` was expected --> $DIR/dyn-call-trait-mismatch.rs:LL:CC | LL | r2.method2(); - | ^^^^^^^^^^^^ `dyn` call on a pointer whose vtable does not match its type + | ^^^^^^^^^^^^ using vtable for trait `T1` but trait `T2` was expected | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs new file mode 100644 index 000000000000..dff5a21c4c77 --- /dev/null +++ b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs @@ -0,0 +1,15 @@ +// This upcast is currently forbidden because it involves an invalid value. +// However, if in the future we relax the validity requirements for raw pointer vtables, +// we could consider allowing this again -- the cast itself isn't doing anything wrong, +// only the transmutes needed to set up the testcase are wrong. + +use std::fmt; + +fn main() { + // vtable_mismatch_nop_cast + let ptr: &dyn fmt::Display = &0; + let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; //~ERROR: wrong trait + // Even though the vtable is for the wrong trait, this cast doesn't actually change the needed + // vtable so it should still be allowed -- if we ever allow the line above. + let _ptr2 = ptr as *const dyn fmt::Debug; +} diff --git a/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr new file mode 100644 index 000000000000..4165d5ea15d9 --- /dev/null +++ b/src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` + --> $DIR/dyn-upcast-nop-wrong-trait.rs:LL:CC + | +LL | let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/dyn-upcast-nop-wrong-trait.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs index 982f33b0a310..1d6b6777032d 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs @@ -1,3 +1,6 @@ +// Validation stops this too early. +//@compile-flags: -Zmiri-disable-validation + #![feature(trait_upcasting)] #![allow(incomplete_features)] @@ -57,7 +60,7 @@ impl Baz for i32 { fn main() { let baz: &dyn Baz = &1; - let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; - let _err = baz_fake as &dyn Foo; - //~^ERROR: upcast on a pointer whose vtable does not match its type + let baz_fake: *const dyn Bar = unsafe { std::mem::transmute(baz) }; + let _err = baz_fake as *const dyn Foo; + //~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected } diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr index 8bac908b864b..6a2415cf57e2 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: upcast on a pointer whose vtable does not match its type +error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC | -LL | let _err = baz_fake as &dyn Foo; - | ^^^^^^^^ upcast on a pointer whose vtable does not match its type +LL | let _err = baz_fake as *const dyn Foo; + | ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.rs new file mode 100644 index 000000000000..9b1cefc4b1d3 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.rs @@ -0,0 +1,12 @@ +use std::mem; + +// Make sure we notice the mismatch also if the difference is "only" in the generic +// parameters of the trait. + +trait Trait {} +impl Trait for T {} + +fn main() { + let x: &dyn Trait = &0; + let _y: *const dyn Trait = unsafe { mem::transmute(x) }; //~ERROR: wrong trait +} diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr new file mode 100644 index 000000000000..1219f9f88cf8 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-generic.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` + --> $DIR/wrong-dyn-trait-generic.rs:LL:CC + | +LL | let _y: *const dyn Trait = unsafe { mem::transmute(x) }; + | ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait`, but encountered `Trait` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/wrong-dyn-trait-generic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs new file mode 100644 index 000000000000..d6049196f266 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs @@ -0,0 +1,6 @@ +use std::{fmt, mem}; + +fn main() { + let x: &dyn Send = &0; + let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) }; //~ERROR: wrong trait +} diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr new file mode 100644 index 000000000000..e3503323b31a --- /dev/null +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `` + --> $DIR/wrong-dyn-trait.rs:LL:CC + | +LL | let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) }; + | ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/wrong-dyn-trait.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs index 2491bda0917d..adbf5df62cc5 100644 --- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -25,7 +25,7 @@ impl Foo for u32 { impl Bar for () {} unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo + 'a)) -> u32 { - let foo_e: *const dyn Foo = t as *const _; + let foo_e: *const dyn Foo = t as *const _; let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index 529b9c471d42..ddc4bdcf082a 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -1,24 +1,26 @@ #![feature(trait_upcasting)] #![allow(incomplete_features)] +use std::fmt; + fn main() { basic(); diamond(); struct_(); replace_vptr(); - vtable_mismatch_nop_cast(); + vtable_nop_cast(); } -fn vtable_mismatch_nop_cast() { - let ptr: &dyn std::fmt::Display = &0; - // Even though the vtable is for the wrong trait, this cast doesn't actually change the needed - // vtable so it should still be allowed. - let ptr: *const (dyn std::fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; - let _ptr2 = ptr as *const dyn std::fmt::Debug; +fn vtable_nop_cast() { + let ptr: &dyn fmt::Debug = &0; + // We transmute things around, but the principal trait does not change, so this is allowed. + let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; + // This cast is a NOP and should be allowed. + let _ptr2 = ptr as *const dyn fmt::Debug; } fn basic() { - trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + trait Foo: PartialEq + fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 } @@ -67,7 +69,7 @@ fn basic() { } let baz: &dyn Baz = &1; - let _: &dyn std::fmt::Debug = baz; + let _: &dyn fmt::Debug = baz; assert_eq!(*baz, 1); assert_eq!(baz.a(), 100); assert_eq!(baz.b(), 200); @@ -77,7 +79,7 @@ fn basic() { assert_eq!(baz.w(), 21); let bar: &dyn Bar = baz; - let _: &dyn std::fmt::Debug = bar; + let _: &dyn fmt::Debug = bar; assert_eq!(*bar, 1); assert_eq!(bar.a(), 100); assert_eq!(bar.b(), 200); @@ -86,14 +88,14 @@ fn basic() { assert_eq!(bar.w(), 21); let foo: &dyn Foo = baz; - let _: &dyn std::fmt::Debug = foo; + let _: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); assert_eq!(foo.z(), 11); assert_eq!(foo.y(), 12); let foo: &dyn Foo = bar; - let _: &dyn std::fmt::Debug = foo; + let _: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); assert_eq!(foo.z(), 11); @@ -101,7 +103,7 @@ fn basic() { } fn diamond() { - trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + trait Foo: PartialEq + fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 } @@ -166,7 +168,7 @@ fn diamond() { } let baz: &dyn Baz = &1; - let _: &dyn std::fmt::Debug = baz; + let _: &dyn fmt::Debug = baz; assert_eq!(*baz, 1); assert_eq!(baz.a(), 100); assert_eq!(baz.b(), 200); @@ -178,7 +180,7 @@ fn diamond() { assert_eq!(baz.v(), 31); let bar1: &dyn Bar1 = baz; - let _: &dyn std::fmt::Debug = bar1; + let _: &dyn fmt::Debug = bar1; assert_eq!(*bar1, 1); assert_eq!(bar1.a(), 100); assert_eq!(bar1.b(), 200); @@ -187,7 +189,7 @@ fn diamond() { assert_eq!(bar1.w(), 21); let bar2: &dyn Bar2 = baz; - let _: &dyn std::fmt::Debug = bar2; + let _: &dyn fmt::Debug = bar2; assert_eq!(*bar2, 1); assert_eq!(bar2.a(), 100); assert_eq!(bar2.c(), 300); @@ -196,17 +198,17 @@ fn diamond() { assert_eq!(bar2.v(), 31); let foo: &dyn Foo = baz; - let _: &dyn std::fmt::Debug = foo; + let _: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); let foo: &dyn Foo = bar1; - let _: &dyn std::fmt::Debug = foo; + let _: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); let foo: &dyn Foo = bar2; - let _: &dyn std::fmt::Debug = foo; + let _: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); } @@ -215,7 +217,7 @@ fn struct_() { use std::rc::Rc; use std::sync::Arc; - trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + trait Foo: PartialEq + fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 } diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs index 410e15d024fa..0d8f92f013fb 100644 --- a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs +++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs @@ -17,7 +17,7 @@ impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } impl Bar for () {} unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo+'a)) -> u32 { - let foo_e : *const dyn Foo = t as *const _; + let foo_e : *const dyn Foo = t as *const _; let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) From 06cd79bb5beee0b240194a80fa8930ca620ea0f5 Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Mon, 22 Apr 2024 09:12:36 +0530 Subject: [PATCH 3/7] Fix ICE when ADT tail has type error --- compiler/rustc_middle/src/ty/layout.rs | 4 ++++ .../layout/ice-type-error-in-tail-124031.rs} | 5 ++++- tests/ui/layout/ice-type-error-in-tail-124031.stderr | 12 ++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) rename tests/{crashes/124031.rs => ui/layout/ice-type-error-in-tail-124031.rs} (54%) create mode 100644 tests/ui/layout/ice-type-error-in-tail-124031.stderr diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6381bd190ac0..897d6f5662f6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -338,6 +338,10 @@ impl<'tcx> SizeSkeleton<'tcx> { debug_assert!(tail.has_non_region_param()); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } + ty::Error(guar) => { + // Fixes ICE #124031 + return Err(tcx.arena.alloc(LayoutError::ReferencesError(*guar))); + } _ => bug!( "SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \ tail `{tail}` is not a type parameter or a projection", diff --git a/tests/crashes/124031.rs b/tests/ui/layout/ice-type-error-in-tail-124031.rs similarity index 54% rename from tests/crashes/124031.rs rename to tests/ui/layout/ice-type-error-in-tail-124031.rs index bdc66fbafe4c..0a2be1174035 100644 --- a/tests/crashes/124031.rs +++ b/tests/ui/layout/ice-type-error-in-tail-124031.rs @@ -1,10 +1,13 @@ -//@ known-bug: #124031 +// Regression test for issue #124031 +// Checks that we don't ICE when the tail +// of an ADT has a type error trait Trait { type RefTarget; } impl Trait for () {} +//~^ ERROR not all trait items implemented, missing: `RefTarget` struct Other { data: <() as Trait>::RefTarget, diff --git a/tests/ui/layout/ice-type-error-in-tail-124031.stderr b/tests/ui/layout/ice-type-error-in-tail-124031.stderr new file mode 100644 index 000000000000..57dc83f92dfd --- /dev/null +++ b/tests/ui/layout/ice-type-error-in-tail-124031.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `RefTarget` + --> $DIR/ice-type-error-in-tail-124031.rs:9:1 + | +LL | type RefTarget; + | -------------- `RefTarget` from trait +... +LL | impl Trait for () {} + | ^^^^^^^^^^^^^^^^^ missing `RefTarget` in implementation + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. From 6bff7f45f1d32d1494cf8ebe48956ca4e5baf315 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 22 Apr 2024 13:11:29 +0000 Subject: [PATCH 4/7] Use `DefiningOpaqueTypes::Yes`, as the `InferCtxt` we use has no opaque types it may define --- compiler/rustc_trait_selection/src/traits/auto_trait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 73e94da165fb..eb6118ba13d9 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -789,7 +789,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::No,c1, c2) + match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::Yes,c1, c2) { Ok(_) => (), Err(_) => return false, From 98332c108b8074954203fa4b0c82fbab876d3059 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sat, 20 Apr 2024 15:52:22 +0200 Subject: [PATCH 5/7] Improve handling of expr->field errors The current message for "`->` used for field access" is the following: ```rust error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `->` --> src/main.rs:2:6 | 2 | a->b; | ^^ expected one of 8 possible tokens ``` (playground link[1]) This PR tries to address this by adding a dedicated error message and recovery. The proposed error message is: ``` error: `->` used for field access or method call --> ./tiny_test.rs:2:6 | 2 | a->b; | ^^ help: try using `.` instead | = help: the `.` operator will dereference the value if needed ``` (feel free to bikeshed it as much as necessary) [1]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7f8b6f4433aa7866124123575456f54e Signed-off-by: Sasha Pourcelot --- compiler/rustc_parse/messages.ftl | 4 ++ compiler/rustc_parse/src/errors.rs | 9 ++++ compiler/rustc_parse/src/parser/expr.rs | 6 +++ tests/ui/parser/expr-rarrow-call.fixed | 33 +++++++++++++++ tests/ui/parser/expr-rarrow-call.rs | 33 +++++++++++++++ tests/ui/parser/expr-rarrow-call.stderr | 42 +++++++++++++++++++ tests/ui/parser/issues/issue-118530-ice.rs | 3 +- .../ui/parser/issues/issue-118530-ice.stderr | 14 +++++-- 8 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 tests/ui/parser/expr-rarrow-call.fixed create mode 100644 tests/ui/parser/expr-rarrow-call.rs create mode 100644 tests/ui/parser/expr-rarrow-call.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e2436759c22c..32a0df2f619a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -230,6 +230,10 @@ parse_expected_struct_field = expected one of `,`, `:`, or `{"}"}`, found `{$tok parse_expected_trait_in_trait_impl_found_type = expected a trait, found type +parse_expr_rarrow_call = `->` used for field access or method call + .suggestion = try using `.` instead + .help = the `.` operator will dereference the value if needed + parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements .label = dash-separated idents are not valid .suggestion = if the original crate name uses dashes you need to use underscores in the code diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index eae2d904c35e..ca8de4240f45 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2988,3 +2988,12 @@ pub(crate) struct AsyncImpl { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_expr_rarrow_call)] +#[help] +pub(crate) struct ExprRArrowCall { + #[primary_span] + #[suggestion(style = "short", applicability = "machine-applicable", code = ".")] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 00947a4c5853..8a4546107186 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -979,6 +979,12 @@ impl<'a> Parser<'a> { // we are using noexpect here because we don't expect a `.` directly after a `return` // which could be suggested otherwise self.eat_noexpect(&token::Dot) + } else if self.token.kind == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(errors::ExprRArrowCall { span }); + true } else { self.eat(&token::Dot) }; diff --git a/tests/ui/parser/expr-rarrow-call.fixed b/tests/ui/parser/expr-rarrow-call.fixed new file mode 100644 index 000000000000..9a05e20092dd --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.fixed @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named.foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed.0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t.0; //~ ERROR `->` used for field access or method call + t.1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo.clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.rs b/tests/ui/parser/expr-rarrow-call.rs new file mode 100644 index 000000000000..760b0f6f345b --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.rs @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named->foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed->0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t->0; //~ ERROR `->` used for field access or method call + t->1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo->clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr new file mode 100644 index 000000000000..90082f98cb5f --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.stderr @@ -0,0 +1,42 @@ +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:14:10 + | +LL | named->foo; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:18:12 + | +LL | unnamed->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:22:6 + | +LL | t->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:23:6 + | +LL | t->1; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:30:8 + | +LL | foo->clone(); + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/issues/issue-118530-ice.rs b/tests/ui/parser/issues/issue-118530-ice.rs index e758e5af4d9e..cf14eebec2b7 100644 --- a/tests/ui/parser/issues/issue-118530-ice.rs +++ b/tests/ui/parser/issues/issue-118530-ice.rs @@ -3,8 +3,9 @@ fn bar() -> String { [1, 2, 3].iter() //~ ERROR expected `;`, found `#` #[feature] attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn` - //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `->` + //~^ ERROR expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` //~| ERROR expected `;`, found `bar` + //~| ERROR `->` used for field access or method call #[attr] [1, 2, 3].iter().map().collect::() #[attr] diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr index ef573fb7ba3d..75c6a40c7445 100644 --- a/tests/ui/parser/issues/issue-118530-ice.stderr +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -33,11 +33,19 @@ LL | attr::fn bar() -> String { | | | help: add `;` here -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `->` +error: `->` used for field access or method call --> $DIR/issue-118530-ice.rs:5:20 | LL | attr::fn bar() -> String { - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` + --> $DIR/issue-118530-ice.rs:5:30 + | +LL | attr::fn bar() -> String { + | ^ expected one of 7 possible tokens -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From 7789874e6ef3ef3515a806c743ec88c503c75cd0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 9 Apr 2024 10:36:58 -0400 Subject: [PATCH 6/7] Deny gen keyword in edition_2024_compat lints --- compiler/rustc_lint/src/builtin.rs | 102 ++++++++++++------ compiler/rustc_lint/src/lib.rs | 4 +- src/tools/lint-docs/src/groups.rs | 4 + src/tools/lint-docs/src/lib.rs | 1 + ...015-edition-error-various-positions.stderr | 1 + .../await-keyword/2015-edition-warning.stderr | 1 + ...dyn-2015-edition-keyword-ident-lint.stderr | 1 + .../lint-pre-expansion-extern-module.stderr | 4 +- tests/ui/rust-2018/async-ident-allowed.stderr | 2 +- tests/ui/rust-2018/async-ident.stderr | 1 + tests/ui/rust-2018/dyn-keyword.stderr | 1 + tests/ui/rust-2018/try-ident.stderr | 2 +- tests/ui/rust-2018/try-macro.stderr | 2 +- tests/ui/rust-2024/gen-kw.e2015.stderr | 26 +++++ tests/ui/rust-2024/gen-kw.e2018.stderr | 26 +++++ tests/ui/rust-2024/gen-kw.rs | 16 +++ 16 files changed, 158 insertions(+), 36 deletions(-) create mode 100644 tests/ui/rust-2024/gen-kw.e2015.stderr create mode 100644 tests/ui/rust-2024/gen-kw.e2018.stderr create mode 100644 tests/ui/rust-2024/gen-kw.rs diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8b974a461d4d..0c89e186c47e 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1769,13 +1769,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } declare_lint! { - /// The `keyword_idents` lint detects edition keywords being used as an + /// The `keyword_idents_2018` lint detects edition keywords being used as an /// identifier. /// /// ### Example /// /// ```rust,edition2015,compile_fail - /// #![deny(keyword_idents)] + /// #![deny(keyword_idents_2018)] /// // edition 2015 /// fn dyn() {} /// ``` @@ -1804,7 +1804,7 @@ declare_lint! { /// [editions]: https://doc.rust-lang.org/edition-guide/ /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html - pub KEYWORD_IDENTS, + pub KEYWORD_IDENTS_2018, Allow, "detects edition keywords being used as an identifier", @future_incompatible = FutureIncompatibleInfo { @@ -1813,9 +1813,54 @@ declare_lint! { }; } +declare_lint! { + /// The `keyword_idents_2024` lint detects edition keywords being used as an + /// identifier. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(keyword_idents_2024)] + /// // edition 2015 + /// fn gen() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses new keywords + /// that are added to the language that are used as identifiers (such as a + /// variable name, function name, etc.). If you switch the compiler to a + /// new edition without updating the code, then it will fail to compile if + /// you are using a new keyword as an identifier. + /// + /// You can manually change the identifiers to a non-keyword, or use a + /// [raw identifier], for example `r#gen`, to transition to a new edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in older editions. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler (which is + /// to use a raw identifier). This provides a completely automated way to + /// update old code for a new edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html + pub KEYWORD_IDENTS_2024, + Allow, + "detects edition keywords being used as an identifier", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #49716 ", + }; +} + declare_lint_pass!( /// Check for uses of edition keywords used as an identifier. - KeywordIdents => [KEYWORD_IDENTS] + KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024] ); struct UnderMacro(bool); @@ -1841,42 +1886,39 @@ impl KeywordIdents { UnderMacro(under_macro): UnderMacro, ident: Ident, ) { - let next_edition = match cx.sess().edition() { - Edition::Edition2015 => { - match ident.name { - kw::Async | kw::Await | kw::Try => Edition::Edition2018, - - // rust-lang/rust#56327: Conservatively do not - // attempt to report occurrences of `dyn` within - // macro definitions or invocations, because `dyn` - // can legitimately occur as a contextual keyword - // in 2015 code denoting its 2018 meaning, and we - // do not want rustfix to inject bugs into working - // code by rewriting such occurrences. - // - // But if we see `dyn` outside of a macro, we know - // its precise role in the parsed AST and thus are - // assured this is truly an attempt to use it as - // an identifier. - kw::Dyn if !under_macro => Edition::Edition2018, - - _ => return, - } - } + let (lint, edition) = match ident.name { + kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018), + + // rust-lang/rust#56327: Conservatively do not + // attempt to report occurrences of `dyn` within + // macro definitions or invocations, because `dyn` + // can legitimately occur as a contextual keyword + // in 2015 code denoting its 2018 meaning, and we + // do not want rustfix to inject bugs into working + // code by rewriting such occurrences. + // + // But if we see `dyn` outside of a macro, we know + // its precise role in the parsed AST and thus are + // assured this is truly an attempt to use it as + // an identifier. + kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018), + + kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024), - // There are no new keywords yet for the 2018 edition and beyond. _ => return, }; // Don't lint `r#foo`. - if cx.sess().psess.raw_identifier_spans.contains(ident.span) { + if ident.span.edition() >= edition + || cx.sess().psess.raw_identifier_spans.contains(ident.span) + { return; } cx.emit_span_lint( - KEYWORD_IDENTS, + lint, ident.span, - BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span }, + BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span }, ); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 31c80c4d75bb..00bc6b24b2a1 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -313,6 +313,8 @@ fn register_builtins(store: &mut LintStore) { // MACRO_USE_EXTERN_CRATE ); + add_lint_group!("keyword_idents", KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024); + add_lint_group!( "refining_impl_trait", REFINING_IMPL_TRAIT_REACHABLE, @@ -325,7 +327,7 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("bare_trait_object", "bare_trait_objects"); store.register_renamed("unstable_name_collision", "unstable_name_collisions"); store.register_renamed("unused_doc_comment", "unused_doc_comments"); - store.register_renamed("async_idents", "keyword_idents"); + store.register_renamed("async_idents", "keyword_idents_2018"); store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 0c39f2fa6010..73f5738469ed 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -20,6 +20,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ "refining-impl-trait", "Detects refinement of `impl Trait` return types by trait implementations", ), + ( + "keyword-idents", + "Lints that detect identifiers which will be come keywords in later editions", + ), ]; type LintGroups = BTreeMap>; diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index aca780e33f0e..22ab576b0776 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -25,6 +25,7 @@ static RENAMES: &[(Level, &[(&str, &str)])] = &[ ("elided-lifetime-in-path", "elided-lifetimes-in-paths"), ("async-idents", "keyword-idents"), ("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"), + ("keyword-idents", "keyword-idents-2018"), ("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"), ], ), diff --git a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr index d99967eb23ca..8cea73f86514 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-error-various-positions.rs:7:20 diff --git a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr index bf5c4d8d6aab..70b7fa52a19c 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `await` is a keyword in the 2018 edition --> $DIR/2015-edition-warning.rs:10:20 diff --git a/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr b/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr index 89aded9134f9..0d53fb024aca 100644 --- a/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr +++ b/tests/ui/dyn-keyword/dyn-2015-edition-keyword-ident-lint.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `dyn` is a keyword in the 2018 edition --> $DIR/dyn-2015-edition-keyword-ident-lint.rs:17:20 diff --git a/tests/ui/lint/lint-pre-expansion-extern-module.stderr b/tests/ui/lint/lint-pre-expansion-extern-module.stderr index 8a6e1531d5fd..32c76da98b52 100644 --- a/tests/ui/lint/lint-pre-expansion-extern-module.stderr +++ b/tests/ui/lint/lint-pre-expansion-extern-module.stderr @@ -6,8 +6,8 @@ LL | pub fn try() {} | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 - = note: `-W keyword-idents` implied by `-W rust-2018-compatibility` - = help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents)]` + = note: `-W keyword-idents-2018` implied by `-W rust-2018-compatibility` + = help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents_2018)]` warning: 1 warning emitted diff --git a/tests/ui/rust-2018/async-ident-allowed.stderr b/tests/ui/rust-2018/async-ident-allowed.stderr index b413c0fd9ba8..378c81d3c770 100644 --- a/tests/ui/rust-2018/async-ident-allowed.stderr +++ b/tests/ui/rust-2018/async-ident-allowed.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(keyword_idents)]` implied by `#[deny(rust_2018_compatibility)]` + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(rust_2018_compatibility)]` error: aborting due to 1 previous error diff --git a/tests/ui/rust-2018/async-ident.stderr b/tests/ui/rust-2018/async-ident.stderr index d15250c54ec9..5b8d8184f4f3 100644 --- a/tests/ui/rust-2018/async-ident.stderr +++ b/tests/ui/rust-2018/async-ident.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:12:7 diff --git a/tests/ui/rust-2018/dyn-keyword.stderr b/tests/ui/rust-2018/dyn-keyword.stderr index 6f9a5ddb14fe..f8245bc88f57 100644 --- a/tests/ui/rust-2018/dyn-keyword.stderr +++ b/tests/ui/rust-2018/dyn-keyword.stderr @@ -11,6 +11,7 @@ note: the lint level is defined here | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: aborting due to 1 previous error diff --git a/tests/ui/rust-2018/try-ident.stderr b/tests/ui/rust-2018/try-ident.stderr index 74015ac9da42..eaf4c235697c 100644 --- a/tests/ui/rust-2018/try-ident.stderr +++ b/tests/ui/rust-2018/try-ident.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![warn(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[warn(keyword_idents)]` implied by `#[warn(rust_2018_compatibility)]` + = note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]` warning: `try` is a keyword in the 2018 edition --> $DIR/try-ident.rs:12:4 diff --git a/tests/ui/rust-2018/try-macro.stderr b/tests/ui/rust-2018/try-macro.stderr index 760378f0955c..095c755539db 100644 --- a/tests/ui/rust-2018/try-macro.stderr +++ b/tests/ui/rust-2018/try-macro.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![warn(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[warn(keyword_idents)]` implied by `#[warn(rust_2018_compatibility)]` + = note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]` warning: 1 warning emitted diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr new file mode 100644 index 000000000000..b12363184b71 --- /dev/null +++ b/tests/ui/rust-2024/gen-kw.e2015.stderr @@ -0,0 +1,26 @@ +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:6:4 + | +LL | fn gen() {} + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 +note: the lint level is defined here + --> $DIR/gen-kw.rs:4:9 + | +LL | #![deny(rust_2024_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2024)]` implied by `#[deny(rust_2024_compatibility)]` + +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:12:9 + | +LL | let gen = r#gen; + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr new file mode 100644 index 000000000000..e10fc4c45120 --- /dev/null +++ b/tests/ui/rust-2024/gen-kw.e2018.stderr @@ -0,0 +1,26 @@ +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:6:4 + | +LL | fn gen() {} + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 +note: the lint level is defined here + --> $DIR/gen-kw.rs:4:9 + | +LL | #![deny(rust_2024_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(keyword_idents_2024)]` implied by `#[deny(rust_2024_compatibility)]` + +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:12:9 + | +LL | let gen = r#gen; + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rust-2024/gen-kw.rs b/tests/ui/rust-2024/gen-kw.rs new file mode 100644 index 000000000000..3d2a3f951655 --- /dev/null +++ b/tests/ui/rust-2024/gen-kw.rs @@ -0,0 +1,16 @@ +//@ revisions: e2015 e2018 +//@[e2018] edition: 2018 + +#![deny(rust_2024_compatibility)] + +fn gen() {} +//~^ ERROR `gen` is a keyword in the 2024 edition +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! +//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + +fn main() { + let gen = r#gen; + //~^ ERROR `gen` is a keyword in the 2024 edition + //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! +} From df437a2af4a47f063642f697f838e529e34c2c57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Apr 2024 17:56:00 +0200 Subject: [PATCH 7/7] remove an unused type from the reentrant lock tests --- library/std/src/sync/reentrant_lock/tests.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/library/std/src/sync/reentrant_lock/tests.rs b/library/std/src/sync/reentrant_lock/tests.rs index d4c1d440c610..aeef0289d28f 100644 --- a/library/std/src/sync/reentrant_lock/tests.rs +++ b/library/std/src/sync/reentrant_lock/tests.rs @@ -1,4 +1,4 @@ -use super::{ReentrantLock, ReentrantLockGuard}; +use super::ReentrantLock; use crate::cell::RefCell; use crate::sync::Arc; use crate::thread; @@ -51,10 +51,3 @@ fn trylock_works() { .unwrap(); let _lock3 = l.try_lock(); } - -pub struct Answer<'a>(pub ReentrantLockGuard<'a, RefCell>); -impl Drop for Answer<'_> { - fn drop(&mut self) { - *self.0.borrow_mut() = 42; - } -}