Auto merge of #124277 - matthiaskrgr:rollup-zdb93i4, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #123680 (Deny gen keyword in `edition_2024_compat` lints) - #124057 (Fix ICE when ADT tail has type error) - #124168 (Use `DefiningOpaqueTypes::Yes` in rustdoc, where the `InferCtxt` is guaranteed to have no opaque types it can define) - #124197 (Move duplicated code in functions in `tests/rustdoc-gui/notable-trait.goml`) - #124200 (Improve handling of expr->field errors) - #124220 (Miri: detect wrong vtables in wide pointers) - #124266 (remove an unused type from the reentrant lock tests) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c67277301c
51 changed files with 672 additions and 252 deletions
|
@ -82,12 +82,6 @@ const_eval_double_storage_live =
|
||||||
const_eval_dyn_call_not_a_method =
|
const_eval_dyn_call_not_a_method =
|
||||||
`dyn` call trying to call something that is 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 ->
|
const_eval_error = {$error_kind ->
|
||||||
[static] could not evaluate static initializer
|
[static] could not evaluate static initializer
|
||||||
[const] evaluation of constant value failed
|
[const] evaluation of constant value failed
|
||||||
|
@ -192,6 +186,8 @@ const_eval_invalid_uninit_bytes_unknown =
|
||||||
const_eval_invalid_vtable_pointer =
|
const_eval_invalid_vtable_pointer =
|
||||||
using {$pointer} as vtable pointer but it does not point to a vtable
|
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 =
|
const_eval_live_drop =
|
||||||
destructor of `{$dropped_ty}` cannot be evaluated at compile-time
|
destructor of `{$dropped_ty}` cannot be evaluated at compile-time
|
||||||
|
@ -401,9 +397,6 @@ const_eval_unterminated_c_string =
|
||||||
const_eval_unwind_past_top =
|
const_eval_unwind_past_top =
|
||||||
unwinding past the topmost frame of the stack
|
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`.
|
## 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...)
|
## (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
|
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_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_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_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_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_never_val = {$front_matter}: encountered a value of the never type `!`
|
||||||
const_eval_validation_null_box = {$front_matter}: encountered a null box
|
const_eval_validation_null_box = {$front_matter}: encountered a null box
|
||||||
|
|
|
@ -498,6 +498,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||||
InvalidTag(_) => const_eval_invalid_tag,
|
InvalidTag(_) => const_eval_invalid_tag,
|
||||||
InvalidFunctionPointer(_) => const_eval_invalid_function_pointer,
|
InvalidFunctionPointer(_) => const_eval_invalid_function_pointer,
|
||||||
InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer,
|
InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer,
|
||||||
|
InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait,
|
||||||
InvalidStr(_) => const_eval_invalid_str,
|
InvalidStr(_) => const_eval_invalid_str,
|
||||||
InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown,
|
InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown,
|
||||||
InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes,
|
InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes,
|
||||||
|
@ -537,6 +538,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||||
| DeadLocal
|
| DeadLocal
|
||||||
| UninhabitedEnumVariantWritten(_)
|
| UninhabitedEnumVariantWritten(_)
|
||||||
| UninhabitedEnumVariantRead(_) => {}
|
| UninhabitedEnumVariantRead(_) => {}
|
||||||
|
|
||||||
BoundsCheckFailed { len, index } => {
|
BoundsCheckFailed { len, index } => {
|
||||||
diag.arg("len", len);
|
diag.arg("len", len);
|
||||||
diag.arg("index", index);
|
diag.arg("index", index);
|
||||||
|
@ -544,6 +546,13 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||||
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
|
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
|
||||||
diag.arg("pointer", 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!("<trivial>")),
|
||||||
|
);
|
||||||
|
}
|
||||||
PointerUseAfterFree(alloc_id, msg) => {
|
PointerUseAfterFree(alloc_id, msg) => {
|
||||||
diag.arg("alloc_id", alloc_id)
|
diag.arg("alloc_id", alloc_id)
|
||||||
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
.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,
|
UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
|
||||||
Uninit { .. } => const_eval_validation_uninit,
|
Uninit { .. } => const_eval_validation_uninit,
|
||||||
InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
|
InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
|
||||||
|
InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait,
|
||||||
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
|
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
|
||||||
const_eval_validation_invalid_box_slice_meta
|
const_eval_validation_invalid_box_slice_meta
|
||||||
}
|
}
|
||||||
|
@ -773,6 +783,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
DanglingPtrNoProvenance { pointer, .. } => {
|
DanglingPtrNoProvenance { pointer, .. } => {
|
||||||
err.arg("pointer", 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!("<trivial>")),
|
||||||
|
);
|
||||||
|
}
|
||||||
NullPtr { .. }
|
NullPtr { .. }
|
||||||
| PtrToStatic { .. }
|
| PtrToStatic { .. }
|
||||||
| ConstRefToMutable
|
| ConstRefToMutable
|
||||||
|
|
|
@ -393,6 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let val = self.read_immediate(src)?;
|
let val = self.read_immediate(src)?;
|
||||||
if data_a.principal() == data_b.principal() {
|
if data_a.principal() == data_b.principal() {
|
||||||
// A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables.
|
// 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);
|
return self.write_immediate(*val, dest);
|
||||||
}
|
}
|
||||||
let (old_data, old_vptr) = val.to_scalar_pair();
|
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 old_vptr = old_vptr.to_pointer(self)?;
|
||||||
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
|
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
|
||||||
if old_trait != data_a.principal() {
|
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())?;
|
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
|
||||||
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
||||||
|
|
|
@ -1020,16 +1020,20 @@ where
|
||||||
pub(super) fn unpack_dyn_trait(
|
pub(super) fn unpack_dyn_trait(
|
||||||
&self,
|
&self,
|
||||||
mplace: &MPlaceTy<'tcx, M::Provenance>,
|
mplace: &MPlaceTy<'tcx, M::Provenance>,
|
||||||
|
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)> {
|
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)> {
|
||||||
assert!(
|
assert!(
|
||||||
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
|
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
|
||||||
"`unpack_dyn_trait` only makes sense on `dyn*` types"
|
"`unpack_dyn_trait` only makes sense on `dyn*` types"
|
||||||
);
|
);
|
||||||
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
|
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
|
||||||
let (ty, _) = self.get_ptr_vtable(vtable)?;
|
let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
|
||||||
let layout = self.layout_of(ty)?;
|
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
|
// This is a kind of transmute, from a place with unsized type and metadata to
|
||||||
// a place with sized type and no metadata.
|
// a place with sized type and no metadata.
|
||||||
|
let layout = self.layout_of(ty)?;
|
||||||
let mplace =
|
let mplace =
|
||||||
MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout };
|
MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout };
|
||||||
Ok((mplace, vtable))
|
Ok((mplace, vtable))
|
||||||
|
@ -1040,6 +1044,7 @@ where
|
||||||
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
|
pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>(
|
||||||
&self,
|
&self,
|
||||||
val: &P,
|
val: &P,
|
||||||
|
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {
|
) -> InterpResult<'tcx, (P, Pointer<Option<M::Provenance>>)> {
|
||||||
assert!(
|
assert!(
|
||||||
matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
|
matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
|
||||||
|
@ -1048,10 +1053,12 @@ where
|
||||||
let data = self.project_field(val, 0)?;
|
let data = self.project_field(val, 0)?;
|
||||||
let vtable = self.project_field(val, 1)?;
|
let vtable = self.project_field(val, 1)?;
|
||||||
let vtable = self.read_pointer(&vtable.to_op(self)?)?;
|
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)?;
|
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)?;
|
let data = data.transmute(layout, self)?;
|
||||||
Ok((data, vtable))
|
Ok((data, vtable))
|
||||||
}
|
}
|
||||||
|
|
|
@ -803,11 +803,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) =
|
let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) =
|
||||||
receiver_place.layout.ty.kind()
|
receiver_place.layout.ty.kind()
|
||||||
{
|
{
|
||||||
let (recv, vptr) = self.unpack_dyn_star(&receiver_place)?;
|
let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?;
|
||||||
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
(vptr, dyn_ty, recv.ptr())
|
(vptr, dyn_ty, recv.ptr())
|
||||||
} else {
|
} else {
|
||||||
|
@ -829,7 +826,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
|
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
|
||||||
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
|
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
|
||||||
if dyn_trait != data.principal() {
|
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
|
// It might be surprising that we use a pointer as the receiver even if this
|
||||||
|
@ -939,13 +939,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let place = self.force_allocation(place)?;
|
let place = self.force_allocation(place)?;
|
||||||
|
|
||||||
let place = match place.layout.ty.kind() {
|
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.
|
// 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.
|
// 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!(
|
debug_assert_eq!(
|
||||||
|
|
|
@ -339,16 +339,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
|
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
|
||||||
match tail.kind() {
|
match tail.kind() {
|
||||||
ty::Dynamic(_, _, ty::Dyn) => {
|
ty::Dynamic(data, _, ty::Dyn) => {
|
||||||
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
|
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
|
||||||
// Make sure it is a genuine vtable pointer.
|
// 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.ecx.get_ptr_vtable(vtable),
|
||||||
self.path,
|
self.path,
|
||||||
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
|
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
|
||||||
InvalidVTablePtr { value: format!("{vtable}") }
|
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 => {
|
ty::Slice(..) | ty::Str => {
|
||||||
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;
|
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 }
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
// Special treatment for special types, where the (static) layout is not sufficient.
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
// If it is a trait object, switch to the real type that was used to create it.
|
// 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
|
// Dyn types. This is unsized, and the actual dynamic type of the data is given by the
|
||||||
// vtable stored in the place metadata.
|
// vtable stored in the place metadata.
|
||||||
// unsized values are never immediate, so we can assert_mem_place
|
// unsized values are never immediate, so we can assert_mem_place
|
||||||
let op = v.to_op(self.ecx())?;
|
let op = v.to_op(self.ecx())?;
|
||||||
let dest = op.assert_mem_place();
|
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);
|
trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
|
||||||
// recurse with the inner type
|
// recurse with the inner type
|
||||||
return self.visit_field(v, 0, &inner_mplace.into());
|
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
|
// 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
|
// 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).
|
// 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);
|
return self.visit_field(v, 0, &data);
|
||||||
}
|
}
|
||||||
// Slices do not need special handling here: they have `Array` field
|
// Slices do not need special handling here: they have `Array` field
|
||||||
|
|
|
@ -1769,13 +1769,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
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.
|
/// identifier.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
///
|
///
|
||||||
/// ```rust,edition2015,compile_fail
|
/// ```rust,edition2015,compile_fail
|
||||||
/// #![deny(keyword_idents)]
|
/// #![deny(keyword_idents_2018)]
|
||||||
/// // edition 2015
|
/// // edition 2015
|
||||||
/// fn dyn() {}
|
/// fn dyn() {}
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -1804,7 +1804,7 @@ declare_lint! {
|
||||||
/// [editions]: https://doc.rust-lang.org/edition-guide/
|
/// [editions]: https://doc.rust-lang.org/edition-guide/
|
||||||
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
|
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
|
||||||
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
|
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
|
||||||
pub KEYWORD_IDENTS,
|
pub KEYWORD_IDENTS_2018,
|
||||||
Allow,
|
Allow,
|
||||||
"detects edition keywords being used as an identifier",
|
"detects edition keywords being used as an identifier",
|
||||||
@future_incompatible = FutureIncompatibleInfo {
|
@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 <https://github.com/rust-lang/rust/issues/49716>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint_pass!(
|
declare_lint_pass!(
|
||||||
/// Check for uses of edition keywords used as an identifier.
|
/// Check for uses of edition keywords used as an identifier.
|
||||||
KeywordIdents => [KEYWORD_IDENTS]
|
KeywordIdents => [KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024]
|
||||||
);
|
);
|
||||||
|
|
||||||
struct UnderMacro(bool);
|
struct UnderMacro(bool);
|
||||||
|
@ -1841,42 +1886,39 @@ impl KeywordIdents {
|
||||||
UnderMacro(under_macro): UnderMacro,
|
UnderMacro(under_macro): UnderMacro,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
) {
|
) {
|
||||||
let next_edition = match cx.sess().edition() {
|
let (lint, edition) = match ident.name {
|
||||||
Edition::Edition2015 => {
|
kw::Async | kw::Await | kw::Try => (KEYWORD_IDENTS_2018, Edition::Edition2018),
|
||||||
match ident.name {
|
|
||||||
kw::Async | kw::Await | kw::Try => Edition::Edition2018,
|
|
||||||
|
|
||||||
// rust-lang/rust#56327: Conservatively do not
|
// rust-lang/rust#56327: Conservatively do not
|
||||||
// attempt to report occurrences of `dyn` within
|
// attempt to report occurrences of `dyn` within
|
||||||
// macro definitions or invocations, because `dyn`
|
// macro definitions or invocations, because `dyn`
|
||||||
// can legitimately occur as a contextual keyword
|
// can legitimately occur as a contextual keyword
|
||||||
// in 2015 code denoting its 2018 meaning, and we
|
// in 2015 code denoting its 2018 meaning, and we
|
||||||
// do not want rustfix to inject bugs into working
|
// do not want rustfix to inject bugs into working
|
||||||
// code by rewriting such occurrences.
|
// code by rewriting such occurrences.
|
||||||
//
|
//
|
||||||
// But if we see `dyn` outside of a macro, we know
|
// But if we see `dyn` outside of a macro, we know
|
||||||
// its precise role in the parsed AST and thus are
|
// its precise role in the parsed AST and thus are
|
||||||
// assured this is truly an attempt to use it as
|
// assured this is truly an attempt to use it as
|
||||||
// an identifier.
|
// an identifier.
|
||||||
kw::Dyn if !under_macro => Edition::Edition2018,
|
kw::Dyn if !under_macro => (KEYWORD_IDENTS_2018, Edition::Edition2018),
|
||||||
|
|
||||||
_ => return,
|
kw::Gen => (KEYWORD_IDENTS_2024, Edition::Edition2024),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are no new keywords yet for the 2018 edition and beyond.
|
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't lint `r#foo`.
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.emit_span_lint(
|
cx.emit_span_lint(
|
||||||
KEYWORD_IDENTS,
|
lint,
|
||||||
ident.span,
|
ident.span,
|
||||||
BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span },
|
BuiltinKeywordIdents { kw: ident, next: edition, suggestion: ident.span },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,6 +312,8 @@ fn register_builtins(store: &mut LintStore) {
|
||||||
// MACRO_USE_EXTERN_CRATE
|
// MACRO_USE_EXTERN_CRATE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_lint_group!("keyword_idents", KEYWORD_IDENTS_2018, KEYWORD_IDENTS_2024);
|
||||||
|
|
||||||
add_lint_group!(
|
add_lint_group!(
|
||||||
"refining_impl_trait",
|
"refining_impl_trait",
|
||||||
REFINING_IMPL_TRAIT_REACHABLE,
|
REFINING_IMPL_TRAIT_REACHABLE,
|
||||||
|
@ -324,7 +326,7 @@ fn register_builtins(store: &mut LintStore) {
|
||||||
store.register_renamed("bare_trait_object", "bare_trait_objects");
|
store.register_renamed("bare_trait_object", "bare_trait_objects");
|
||||||
store.register_renamed("unstable_name_collision", "unstable_name_collisions");
|
store.register_renamed("unstable_name_collision", "unstable_name_collisions");
|
||||||
store.register_renamed("unused_doc_comment", "unused_doc_comments");
|
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("exceeding_bitshifts", "arithmetic_overflow");
|
||||||
store.register_renamed("redundant_semicolon", "redundant_semicolons");
|
store.register_renamed("redundant_semicolon", "redundant_semicolons");
|
||||||
store.register_renamed("overlapping_patterns", "overlapping_range_endpoints");
|
store.register_renamed("overlapping_patterns", "overlapping_range_endpoints");
|
||||||
|
|
|
@ -2,7 +2,7 @@ use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar};
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::mir::{ConstAlloc, ConstValue};
|
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_ast_ir::Mutability;
|
||||||
use rustc_data_structures::sync::Lock;
|
use rustc_data_structures::sync::Lock;
|
||||||
|
@ -344,6 +344,11 @@ pub enum UndefinedBehaviorInfo<'tcx> {
|
||||||
InvalidFunctionPointer(Pointer<AllocId>),
|
InvalidFunctionPointer(Pointer<AllocId>),
|
||||||
/// Using a pointer-not-to-a-vtable as vtable pointer.
|
/// Using a pointer-not-to-a-vtable as vtable pointer.
|
||||||
InvalidVTablePointer(Pointer<AllocId>),
|
InvalidVTablePointer(Pointer<AllocId>),
|
||||||
|
/// Using a vtable for the wrong trait.
|
||||||
|
InvalidVTableTrait {
|
||||||
|
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
|
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||||
|
},
|
||||||
/// Using a string that is not valid UTF-8,
|
/// Using a string that is not valid UTF-8,
|
||||||
InvalidStr(std::str::Utf8Error),
|
InvalidStr(std::str::Utf8Error),
|
||||||
/// Using uninitialized data where it is not allowed.
|
/// Using uninitialized data where it is not allowed.
|
||||||
|
@ -414,34 +419,86 @@ impl From<PointerKind> for ExpectedKind {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ValidationErrorKind<'tcx> {
|
pub enum ValidationErrorKind<'tcx> {
|
||||||
PointerAsInt { expected: ExpectedKind },
|
PointerAsInt {
|
||||||
|
expected: ExpectedKind,
|
||||||
|
},
|
||||||
PartialPointer,
|
PartialPointer,
|
||||||
PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
|
PtrToUninhabited {
|
||||||
PtrToStatic { ptr_kind: PointerKind },
|
ptr_kind: PointerKind,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
},
|
||||||
|
PtrToStatic {
|
||||||
|
ptr_kind: PointerKind,
|
||||||
|
},
|
||||||
ConstRefToMutable,
|
ConstRefToMutable,
|
||||||
ConstRefToExtern,
|
ConstRefToExtern,
|
||||||
MutableRefToImmutable,
|
MutableRefToImmutable,
|
||||||
UnsafeCellInImmutable,
|
UnsafeCellInImmutable,
|
||||||
NullFnPtr,
|
NullFnPtr,
|
||||||
NeverVal,
|
NeverVal,
|
||||||
NullablePtrOutOfRange { range: WrappingRange, max_value: u128 },
|
NullablePtrOutOfRange {
|
||||||
PtrOutOfRange { range: WrappingRange, max_value: u128 },
|
range: WrappingRange,
|
||||||
OutOfRange { value: String, range: WrappingRange, max_value: u128 },
|
max_value: u128,
|
||||||
UninhabitedVal { ty: Ty<'tcx> },
|
},
|
||||||
InvalidEnumTag { value: String },
|
PtrOutOfRange {
|
||||||
|
range: WrappingRange,
|
||||||
|
max_value: u128,
|
||||||
|
},
|
||||||
|
OutOfRange {
|
||||||
|
value: String,
|
||||||
|
range: WrappingRange,
|
||||||
|
max_value: u128,
|
||||||
|
},
|
||||||
|
UninhabitedVal {
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
},
|
||||||
|
InvalidEnumTag {
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
UninhabitedEnumVariant,
|
UninhabitedEnumVariant,
|
||||||
Uninit { expected: ExpectedKind },
|
Uninit {
|
||||||
InvalidVTablePtr { value: String },
|
expected: ExpectedKind,
|
||||||
InvalidMetaSliceTooLarge { ptr_kind: PointerKind },
|
},
|
||||||
InvalidMetaTooLarge { ptr_kind: PointerKind },
|
InvalidVTablePtr {
|
||||||
UnalignedPtr { ptr_kind: PointerKind, required_bytes: u64, found_bytes: u64 },
|
value: String,
|
||||||
NullPtr { ptr_kind: PointerKind },
|
},
|
||||||
DanglingPtrNoProvenance { ptr_kind: PointerKind, pointer: String },
|
InvalidMetaWrongTrait {
|
||||||
DanglingPtrOutOfBounds { ptr_kind: PointerKind },
|
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
DanglingPtrUseAfterFree { ptr_kind: PointerKind },
|
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||||
InvalidBool { value: String },
|
},
|
||||||
InvalidChar { value: String },
|
InvalidMetaSliceTooLarge {
|
||||||
InvalidFnPtr { value: String },
|
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
|
/// Error information for when the program did something that might (or might not) be correct
|
||||||
|
|
|
@ -338,6 +338,10 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
||||||
debug_assert!(tail.has_non_region_param());
|
debug_assert!(tail.has_non_region_param());
|
||||||
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
|
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!(
|
_ => bug!(
|
||||||
"SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \
|
"SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \
|
||||||
tail `{tail}` is not a type parameter or a projection",
|
tail `{tail}` is not a type parameter or a projection",
|
||||||
|
|
|
@ -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_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
|
parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
|
||||||
.label = dash-separated idents are not valid
|
.label = dash-separated idents are not valid
|
||||||
.suggestion = if the original crate name uses dashes you need to use underscores in the code
|
.suggestion = if the original crate name uses dashes you need to use underscores in the code
|
||||||
|
|
|
@ -2988,3 +2988,12 @@ pub(crate) struct AsyncImpl {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: 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,
|
||||||
|
}
|
||||||
|
|
|
@ -979,6 +979,12 @@ impl<'a> Parser<'a> {
|
||||||
// we are using noexpect here because we don't expect a `.` directly after a `return`
|
// we are using noexpect here because we don't expect a `.` directly after a `return`
|
||||||
// which could be suggested otherwise
|
// which could be suggested otherwise
|
||||||
self.eat_noexpect(&token::Dot)
|
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 {
|
} else {
|
||||||
self.eat(&token::Dot)
|
self.eat(&token::Dot)
|
||||||
};
|
};
|
||||||
|
|
|
@ -784,7 +784,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||||
|
|
||||||
match (evaluate(c1), evaluate(c2)) {
|
match (evaluate(c1), evaluate(c2)) {
|
||||||
(Ok(c1), Ok(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(_) => (),
|
Ok(_) => (),
|
||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{ReentrantLock, ReentrantLockGuard};
|
use super::ReentrantLock;
|
||||||
use crate::cell::RefCell;
|
use crate::cell::RefCell;
|
||||||
use crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::thread;
|
use crate::thread;
|
||||||
|
@ -51,10 +51,3 @@ fn trylock_works() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let _lock3 = l.try_lock();
|
let _lock3 = l.try_lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Answer<'a>(pub ReentrantLockGuard<'a, RefCell<u32>>);
|
|
||||||
impl Drop for Answer<'_> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
*self.0.borrow_mut() = 42;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,6 +20,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
|
||||||
"refining-impl-trait",
|
"refining-impl-trait",
|
||||||
"Detects refinement of `impl Trait` return types by trait implementations",
|
"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<String, BTreeSet<String>>;
|
type LintGroups = BTreeMap<String, BTreeSet<String>>;
|
||||||
|
|
|
@ -25,6 +25,7 @@ static RENAMES: &[(Level, &[(&str, &str)])] = &[
|
||||||
("elided-lifetime-in-path", "elided-lifetimes-in-paths"),
|
("elided-lifetime-in-path", "elided-lifetimes-in-paths"),
|
||||||
("async-idents", "keyword-idents"),
|
("async-idents", "keyword-idents"),
|
||||||
("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"),
|
("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"),
|
||||||
|
("keyword-idents", "keyword-idents-2018"),
|
||||||
("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"),
|
("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Validation stops this too early.
|
||||||
|
//@compile-flags: -Zmiri-disable-validation
|
||||||
|
|
||||||
trait T1 {
|
trait T1 {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn method1(self: Box<Self>);
|
fn method1(self: Box<Self>);
|
||||||
|
@ -13,5 +16,5 @@ impl T1 for i32 {
|
||||||
fn main() {
|
fn main() {
|
||||||
let r = Box::new(0) as Box<dyn T1>;
|
let r = Box::new(0) as Box<dyn T1>;
|
||||||
let r2: Box<dyn T2> = unsafe { std::mem::transmute(r) };
|
let r2: Box<dyn T2> = 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
--> $DIR/dyn-call-trait-mismatch.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | r2.method2();
|
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: 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
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
|
15
src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs
Normal file
15
src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.rs
Normal file
|
@ -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;
|
||||||
|
}
|
15
src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr
Normal file
15
src/tools/miri/tests/fail/dyn-upcast-nop-wrong-trait.stderr
Normal file
|
@ -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
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Validation stops this too early.
|
||||||
|
//@compile-flags: -Zmiri-disable-validation
|
||||||
|
|
||||||
#![feature(trait_upcasting)]
|
#![feature(trait_upcasting)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
@ -57,7 +60,7 @@ impl Baz for i32 {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let baz: &dyn Baz = &1;
|
let baz: &dyn Baz = &1;
|
||||||
let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) };
|
let baz_fake: *const dyn Bar = unsafe { std::mem::transmute(baz) };
|
||||||
let _err = baz_fake as &dyn Foo;
|
let _err = baz_fake as *const dyn Foo;
|
||||||
//~^ERROR: upcast on a pointer whose vtable does not match its type
|
//~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
--> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | let _err = baz_fake as &dyn Foo;
|
LL | let _err = baz_fake as *const dyn Foo;
|
||||||
| ^^^^^^^^ upcast on a pointer whose vtable does not match its type
|
| ^^^^^^^^ 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: 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
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
|
|
@ -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<T> {}
|
||||||
|
impl<T> Trait<T> for T {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x: &dyn Trait<i32> = &0;
|
||||||
|
let _y: *const dyn Trait<u32> = unsafe { mem::transmute(x) }; //~ERROR: wrong trait
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<u32>`, but encountered `Trait<i32>`
|
||||||
|
--> $DIR/wrong-dyn-trait-generic.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let _y: *const dyn Trait<u32> = unsafe { mem::transmute(x) };
|
||||||
|
| ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<u32>`, but encountered `Trait<i32>`
|
||||||
|
|
|
||||||
|
= 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
|
||||||
|
|
6
src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs
Normal file
6
src/tools/miri/tests/fail/validity/wrong-dyn-trait.rs
Normal file
|
@ -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
|
||||||
|
}
|
15
src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
Normal file
15
src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
|
||||||
|
--> $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 `<trivial>`
|
||||||
|
|
|
||||||
|
= 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
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl Foo<u32> for u32 {
|
||||||
impl Bar for () {}
|
impl Bar for () {}
|
||||||
|
|
||||||
unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32> + 'a)) -> u32 {
|
unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32> + 'a)) -> u32 {
|
||||||
let foo_e: *const dyn Foo<u16> = t as *const _;
|
let foo_e: *const dyn Foo<u32> = t as *const _;
|
||||||
let r_1 = foo_e as *mut dyn Foo<u32>;
|
let r_1 = foo_e as *mut dyn Foo<u32>;
|
||||||
|
|
||||||
(&*r_1).foo(0)
|
(&*r_1).foo(0)
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
#![feature(trait_upcasting)]
|
#![feature(trait_upcasting)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
basic();
|
basic();
|
||||||
diamond();
|
diamond();
|
||||||
struct_();
|
struct_();
|
||||||
replace_vptr();
|
replace_vptr();
|
||||||
vtable_mismatch_nop_cast();
|
vtable_nop_cast();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vtable_mismatch_nop_cast() {
|
fn vtable_nop_cast() {
|
||||||
let ptr: &dyn std::fmt::Display = &0;
|
let ptr: &dyn fmt::Debug = &0;
|
||||||
// Even though the vtable is for the wrong trait, this cast doesn't actually change the needed
|
// We transmute things around, but the principal trait does not change, so this is allowed.
|
||||||
// vtable so it should still be allowed.
|
let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) };
|
||||||
let ptr: *const (dyn std::fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) };
|
// This cast is a NOP and should be allowed.
|
||||||
let _ptr2 = ptr as *const dyn std::fmt::Debug;
|
let _ptr2 = ptr as *const dyn fmt::Debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn basic() {
|
fn basic() {
|
||||||
trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
|
trait Foo: PartialEq<i32> + fmt::Debug + Send + Sync {
|
||||||
fn a(&self) -> i32 {
|
fn a(&self) -> i32 {
|
||||||
10
|
10
|
||||||
}
|
}
|
||||||
|
@ -67,7 +69,7 @@ fn basic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let baz: &dyn Baz = &1;
|
let baz: &dyn Baz = &1;
|
||||||
let _: &dyn std::fmt::Debug = baz;
|
let _: &dyn fmt::Debug = baz;
|
||||||
assert_eq!(*baz, 1);
|
assert_eq!(*baz, 1);
|
||||||
assert_eq!(baz.a(), 100);
|
assert_eq!(baz.a(), 100);
|
||||||
assert_eq!(baz.b(), 200);
|
assert_eq!(baz.b(), 200);
|
||||||
|
@ -77,7 +79,7 @@ fn basic() {
|
||||||
assert_eq!(baz.w(), 21);
|
assert_eq!(baz.w(), 21);
|
||||||
|
|
||||||
let bar: &dyn Bar = baz;
|
let bar: &dyn Bar = baz;
|
||||||
let _: &dyn std::fmt::Debug = bar;
|
let _: &dyn fmt::Debug = bar;
|
||||||
assert_eq!(*bar, 1);
|
assert_eq!(*bar, 1);
|
||||||
assert_eq!(bar.a(), 100);
|
assert_eq!(bar.a(), 100);
|
||||||
assert_eq!(bar.b(), 200);
|
assert_eq!(bar.b(), 200);
|
||||||
|
@ -86,14 +88,14 @@ fn basic() {
|
||||||
assert_eq!(bar.w(), 21);
|
assert_eq!(bar.w(), 21);
|
||||||
|
|
||||||
let foo: &dyn Foo = baz;
|
let foo: &dyn Foo = baz;
|
||||||
let _: &dyn std::fmt::Debug = foo;
|
let _: &dyn fmt::Debug = foo;
|
||||||
assert_eq!(*foo, 1);
|
assert_eq!(*foo, 1);
|
||||||
assert_eq!(foo.a(), 100);
|
assert_eq!(foo.a(), 100);
|
||||||
assert_eq!(foo.z(), 11);
|
assert_eq!(foo.z(), 11);
|
||||||
assert_eq!(foo.y(), 12);
|
assert_eq!(foo.y(), 12);
|
||||||
|
|
||||||
let foo: &dyn Foo = bar;
|
let foo: &dyn Foo = bar;
|
||||||
let _: &dyn std::fmt::Debug = foo;
|
let _: &dyn fmt::Debug = foo;
|
||||||
assert_eq!(*foo, 1);
|
assert_eq!(*foo, 1);
|
||||||
assert_eq!(foo.a(), 100);
|
assert_eq!(foo.a(), 100);
|
||||||
assert_eq!(foo.z(), 11);
|
assert_eq!(foo.z(), 11);
|
||||||
|
@ -101,7 +103,7 @@ fn basic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diamond() {
|
fn diamond() {
|
||||||
trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
|
trait Foo: PartialEq<i32> + fmt::Debug + Send + Sync {
|
||||||
fn a(&self) -> i32 {
|
fn a(&self) -> i32 {
|
||||||
10
|
10
|
||||||
}
|
}
|
||||||
|
@ -166,7 +168,7 @@ fn diamond() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let baz: &dyn Baz = &1;
|
let baz: &dyn Baz = &1;
|
||||||
let _: &dyn std::fmt::Debug = baz;
|
let _: &dyn fmt::Debug = baz;
|
||||||
assert_eq!(*baz, 1);
|
assert_eq!(*baz, 1);
|
||||||
assert_eq!(baz.a(), 100);
|
assert_eq!(baz.a(), 100);
|
||||||
assert_eq!(baz.b(), 200);
|
assert_eq!(baz.b(), 200);
|
||||||
|
@ -178,7 +180,7 @@ fn diamond() {
|
||||||
assert_eq!(baz.v(), 31);
|
assert_eq!(baz.v(), 31);
|
||||||
|
|
||||||
let bar1: &dyn Bar1 = baz;
|
let bar1: &dyn Bar1 = baz;
|
||||||
let _: &dyn std::fmt::Debug = bar1;
|
let _: &dyn fmt::Debug = bar1;
|
||||||
assert_eq!(*bar1, 1);
|
assert_eq!(*bar1, 1);
|
||||||
assert_eq!(bar1.a(), 100);
|
assert_eq!(bar1.a(), 100);
|
||||||
assert_eq!(bar1.b(), 200);
|
assert_eq!(bar1.b(), 200);
|
||||||
|
@ -187,7 +189,7 @@ fn diamond() {
|
||||||
assert_eq!(bar1.w(), 21);
|
assert_eq!(bar1.w(), 21);
|
||||||
|
|
||||||
let bar2: &dyn Bar2 = baz;
|
let bar2: &dyn Bar2 = baz;
|
||||||
let _: &dyn std::fmt::Debug = bar2;
|
let _: &dyn fmt::Debug = bar2;
|
||||||
assert_eq!(*bar2, 1);
|
assert_eq!(*bar2, 1);
|
||||||
assert_eq!(bar2.a(), 100);
|
assert_eq!(bar2.a(), 100);
|
||||||
assert_eq!(bar2.c(), 300);
|
assert_eq!(bar2.c(), 300);
|
||||||
|
@ -196,17 +198,17 @@ fn diamond() {
|
||||||
assert_eq!(bar2.v(), 31);
|
assert_eq!(bar2.v(), 31);
|
||||||
|
|
||||||
let foo: &dyn Foo = baz;
|
let foo: &dyn Foo = baz;
|
||||||
let _: &dyn std::fmt::Debug = foo;
|
let _: &dyn fmt::Debug = foo;
|
||||||
assert_eq!(*foo, 1);
|
assert_eq!(*foo, 1);
|
||||||
assert_eq!(foo.a(), 100);
|
assert_eq!(foo.a(), 100);
|
||||||
|
|
||||||
let foo: &dyn Foo = bar1;
|
let foo: &dyn Foo = bar1;
|
||||||
let _: &dyn std::fmt::Debug = foo;
|
let _: &dyn fmt::Debug = foo;
|
||||||
assert_eq!(*foo, 1);
|
assert_eq!(*foo, 1);
|
||||||
assert_eq!(foo.a(), 100);
|
assert_eq!(foo.a(), 100);
|
||||||
|
|
||||||
let foo: &dyn Foo = bar2;
|
let foo: &dyn Foo = bar2;
|
||||||
let _: &dyn std::fmt::Debug = foo;
|
let _: &dyn fmt::Debug = foo;
|
||||||
assert_eq!(*foo, 1);
|
assert_eq!(*foo, 1);
|
||||||
assert_eq!(foo.a(), 100);
|
assert_eq!(foo.a(), 100);
|
||||||
}
|
}
|
||||||
|
@ -215,7 +217,7 @@ fn struct_() {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
|
trait Foo: PartialEq<i32> + fmt::Debug + Send + Sync {
|
||||||
fn a(&self) -> i32 {
|
fn a(&self) -> i32 {
|
||||||
10
|
10
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,47 +2,70 @@
|
||||||
include: "utils.goml"
|
include: "utils.goml"
|
||||||
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"
|
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"
|
||||||
show-text: true
|
show-text: true
|
||||||
|
|
||||||
|
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|},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// We start with a wide screen.
|
// We start with a wide screen.
|
||||||
set-window-size: (1100, 600)
|
set-window-size: (1100, 600)
|
||||||
// Checking they have the same y position.
|
call-function: ("check-notable-tooltip-position-complete", {
|
||||||
compare-elements-position: (
|
"x": 677,
|
||||||
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
|
"i_x": 955,
|
||||||
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
|
"popover_x": 463,
|
||||||
["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}
|
|
||||||
)
|
|
||||||
compare-elements-position-false: (
|
|
||||||
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
|
|
||||||
"//*[@class='tooltip popover']",
|
|
||||||
["x"]
|
|
||||||
)
|
|
||||||
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
|
|
||||||
move-cursor-to: "//h1"
|
|
||||||
assert-count: ("//*[@class='tooltip popover']", 0)
|
|
||||||
|
|
||||||
// Now only the `i` should be on the next line.
|
// Now only the `i` should be on the next line.
|
||||||
set-window-size: (1055, 600)
|
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.
|
// Now both the `i` and the struct name should be on the next line.
|
||||||
set-window-size: (980, 600)
|
set-window-size: (980, 600)
|
||||||
// Checking they have the same y position.
|
call-function: ("check-notable-tooltip-position", {
|
||||||
compare-elements-position: (
|
"x": 245,
|
||||||
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
|
"i_x": 523,
|
||||||
"//*[@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},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Checking on mobile now.
|
// Checking on mobile now.
|
||||||
set-window-size: (650, 600)
|
set-window-size: (650, 600)
|
||||||
// Checking they have the same y position.
|
call-function: ("check-notable-tooltip-position-complete", {
|
||||||
compare-elements-position: (
|
"x": 15,
|
||||||
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
|
"i_x": 293,
|
||||||
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
|
"popover_x": 0,
|
||||||
["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)
|
|
||||||
|
|
||||||
// Now check the colors.
|
// Now check the colors.
|
||||||
define-function: (
|
define-function: (
|
||||||
|
@ -236,31 +206,31 @@ press-key: "Tab"
|
||||||
assert-count: ("//*[@class='tooltip popover']", 0)
|
assert-count: ("//*[@class='tooltip popover']", 0)
|
||||||
assert: "#method\.create_an_iterator_from_read .tooltip:focus"
|
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
|
// Now we check that the focus isn't given back to the wrong item when opening
|
||||||
// another popover.
|
// another popover.
|
||||||
store-window-property: {"scrollY": scroll}
|
call-function: ("setup-popup", {})
|
||||||
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"
|
|
||||||
click: ".search-input"
|
click: ".search-input"
|
||||||
// We ensure we didn't come back to the previous focused item.
|
// We ensure we didn't come back to the previous focused item.
|
||||||
assert-window-property-false: {"scrollY": |scroll|}
|
assert-window-property-false: {"scrollY": |scroll|}
|
||||||
|
|
||||||
// Same but with Escape handling.
|
// Same but with Escape handling.
|
||||||
store-window-property: {"scrollY": scroll}
|
call-function: ("setup-popup", {})
|
||||||
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"
|
|
||||||
press-key: "Escape"
|
press-key: "Escape"
|
||||||
// We ensure we didn't come back to the previous focused item.
|
// We ensure we didn't come back to the previous focused item.
|
||||||
assert-window-property-false: {"scrollY": |scroll|}
|
assert-window-property-false: {"scrollY": |scroll|}
|
||||||
|
|
|
@ -11,6 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![deny(keyword_idents)]
|
LL | #![deny(keyword_idents)]
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
|
||||||
|
|
||||||
error: `await` is a keyword in the 2018 edition
|
error: `await` is a keyword in the 2018 edition
|
||||||
--> $DIR/2015-edition-error-various-positions.rs:7:20
|
--> $DIR/2015-edition-error-various-positions.rs:7:20
|
||||||
|
|
|
@ -11,6 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![deny(keyword_idents)]
|
LL | #![deny(keyword_idents)]
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
|
||||||
|
|
||||||
error: `await` is a keyword in the 2018 edition
|
error: `await` is a keyword in the 2018 edition
|
||||||
--> $DIR/2015-edition-warning.rs:10:20
|
--> $DIR/2015-edition-warning.rs:10:20
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
|
||||||
impl Bar for () {}
|
impl Bar for () {}
|
||||||
|
|
||||||
unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32>+'a)) -> u32 {
|
unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32>+'a)) -> u32 {
|
||||||
let foo_e : *const dyn Foo<u16> = t as *const _;
|
let foo_e : *const dyn Foo<u32> = t as *const _;
|
||||||
let r_1 = foo_e as *mut dyn Foo<u32>;
|
let r_1 = foo_e as *mut dyn Foo<u32>;
|
||||||
|
|
||||||
(&*r_1).foo(0)
|
(&*r_1).foo(0)
|
||||||
|
|
|
@ -11,6 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![deny(keyword_idents)]
|
LL | #![deny(keyword_idents)]
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
|
||||||
|
|
||||||
error: `dyn` is a keyword in the 2018 edition
|
error: `dyn` is a keyword in the 2018 edition
|
||||||
--> $DIR/dyn-2015-edition-keyword-ident-lint.rs:17:20
|
--> $DIR/dyn-2015-edition-keyword-ident-lint.rs:17:20
|
||||||
|
|
|
@ -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 {
|
trait Trait {
|
||||||
type RefTarget;
|
type RefTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trait for () {}
|
impl Trait for () {}
|
||||||
|
//~^ ERROR not all trait items implemented, missing: `RefTarget`
|
||||||
|
|
||||||
struct Other {
|
struct Other {
|
||||||
data: <() as Trait>::RefTarget,
|
data: <() as Trait>::RefTarget,
|
12
tests/ui/layout/ice-type-error-in-tail-124031.stderr
Normal file
12
tests/ui/layout/ice-type-error-in-tail-124031.stderr
Normal file
|
@ -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`.
|
|
@ -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!
|
= 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 <https://github.com/rust-lang/rust/issues/49716>
|
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
|
||||||
= note: `-W keyword-idents` implied by `-W rust-2018-compatibility`
|
= note: `-W keyword-idents-2018` implied by `-W rust-2018-compatibility`
|
||||||
= help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents)]`
|
= help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents_2018)]`
|
||||||
|
|
||||||
warning: 1 warning emitted
|
warning: 1 warning emitted
|
||||||
|
|
||||||
|
|
33
tests/ui/parser/expr-rarrow-call.fixed
Normal file
33
tests/ui/parser/expr-rarrow-call.fixed
Normal file
|
@ -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() {}
|
33
tests/ui/parser/expr-rarrow-call.rs
Normal file
33
tests/ui/parser/expr-rarrow-call.rs
Normal file
|
@ -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() {}
|
42
tests/ui/parser/expr-rarrow-call.stderr
Normal file
42
tests/ui/parser/expr-rarrow-call.stderr
Normal file
|
@ -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
|
||||||
|
|
|
@ -3,8 +3,9 @@ fn bar() -> String {
|
||||||
[1, 2, 3].iter() //~ ERROR expected `;`, found `#`
|
[1, 2, 3].iter() //~ ERROR expected `;`, found `#`
|
||||||
#[feature]
|
#[feature]
|
||||||
attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn`
|
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 expected `;`, found `bar`
|
||||||
|
//~| ERROR `->` used for field access or method call
|
||||||
#[attr]
|
#[attr]
|
||||||
[1, 2, 3].iter().map().collect::<String>()
|
[1, 2, 3].iter().map().collect::<String>()
|
||||||
#[attr]
|
#[attr]
|
||||||
|
|
|
@ -33,11 +33,19 @@ LL | attr::fn bar() -> String {
|
||||||
| |
|
| |
|
||||||
| help: add `;` here
|
| 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
|
--> $DIR/issue-118530-ice.rs:5:20
|
||||||
|
|
|
|
||||||
LL | attr::fn bar() -> String {
|
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: aborting due to 4 previous errors
|
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 5 previous errors
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![deny(rust_2018_compatibility)]
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![deny(keyword_idents)]
|
LL | #![deny(keyword_idents)]
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
|
||||||
|
|
||||||
error: `async` is a keyword in the 2018 edition
|
error: `async` is a keyword in the 2018 edition
|
||||||
--> $DIR/async-ident.rs:12:7
|
--> $DIR/async-ident.rs:12:7
|
||||||
|
|
|
@ -11,6 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![deny(keyword_idents)]
|
LL | #![deny(keyword_idents)]
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![warn(rust_2018_compatibility)]
|
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
|
warning: `try` is a keyword in the 2018 edition
|
||||||
--> $DIR/try-ident.rs:12:4
|
--> $DIR/try-ident.rs:12:4
|
||||||
|
|
|
@ -11,7 +11,7 @@ note: the lint level is defined here
|
||||||
|
|
|
|
||||||
LL | #![warn(rust_2018_compatibility)]
|
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
|
warning: 1 warning emitted
|
||||||
|
|
||||||
|
|
26
tests/ui/rust-2024/gen-kw.e2015.stderr
Normal file
26
tests/ui/rust-2024/gen-kw.e2015.stderr
Normal file
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/49716>
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
26
tests/ui/rust-2024/gen-kw.e2018.stderr
Normal file
26
tests/ui/rust-2024/gen-kw.e2018.stderr
Normal file
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/49716>
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
16
tests/ui/rust-2024/gen-kw.rs
Normal file
16
tests/ui/rust-2024/gen-kw.rs
Normal file
|
@ -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!
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue