Auto merge of #72756 - RalfJung:rollup-tbjmtx2, r=RalfJung
Rollup of 9 pull requests Successful merges: - #67460 (Tweak impl signature mismatch errors involving `RegionKind::ReVar` lifetimes) - #71095 (impl From<[T; N]> for Box<[T]>) - #71500 (Make pointer offset methods/intrinsics const) - #71804 (linker: Support `-static-pie` and `-static -shared`) - #71862 (Implement RFC 2585: unsafe blocks in unsafe fn) - #72103 (borrowck `DefId` -> `LocalDefId`) - #72407 (Various minor improvements to Ipv6Addr::Display) - #72413 (impl Step for char (make Range*<char> iterable)) - #72439 (NVPTX support for new asm!) Failed merges: r? @ghost
This commit is contained in:
commit
0e9e408310
|
@ -468,12 +468,17 @@ Here is the list of currently supported register classes:
|
|||
| ARM | `qreg` | `q[0-15]` | `w` |
|
||||
| ARM | `qreg_low8` | `q[0-7]` | `t` |
|
||||
| ARM | `qreg_low4` | `q[0-3]` | `x` |
|
||||
| NVPTX | `reg16` | None\* | `h` |
|
||||
| NVPTX | `reg32` | None\* | `r` |
|
||||
| NVPTX | `reg64` | None\* | `l` |
|
||||
| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
|
||||
| RISC-V | `freg` | `f[0-31]` | `f` |
|
||||
|
||||
> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
|
||||
>
|
||||
> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
|
||||
>
|
||||
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
|
||||
|
||||
Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
|
||||
|
||||
|
@ -495,6 +500,9 @@ Each register class has constraints on which value types they can be used with.
|
|||
| ARM | `sreg` | `vfp2` | `i32`, `f32` |
|
||||
| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
|
||||
| ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
|
||||
| NVPTX | `reg16` | None | `i8`, `i16` |
|
||||
| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
|
||||
| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
|
||||
| RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
|
||||
| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
|
||||
| RISC-V | `freg` | `f` | `f32` |
|
||||
|
@ -610,6 +618,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
|
|||
| ARM | `dreg` | None | `d0` | `P` |
|
||||
| ARM | `qreg` | None | `q0` | `q` |
|
||||
| ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
|
||||
| NVPTX | `reg16` | None | `rs0` | None |
|
||||
| NVPTX | `reg32` | None | `r0` | None |
|
||||
| NVPTX | `reg64` | None | `rd0` | None |
|
||||
| RISC-V | `reg` | None | `x1` | None |
|
||||
| RISC-V | `freg` | None | `f0` | None |
|
||||
|
||||
|
|
|
@ -865,6 +865,25 @@ impl From<Box<str>> for Box<[u8]> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "box_from_array", since = "1.45.0")]
|
||||
impl<T, const N: usize> From<[T; N]> for Box<[T]>
|
||||
where
|
||||
[T; N]: LengthAtMost32,
|
||||
{
|
||||
/// Converts a `[T; N]` into a `Box<[T]>`
|
||||
///
|
||||
/// This conversion moves the array to newly heap-allocated memory.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
/// let boxed: Box<[u8]> = Box::from([4, 2]);
|
||||
/// println!("{:?}", boxed);
|
||||
/// ```
|
||||
fn from(array: [T; N]) -> Box<[T]> {
|
||||
box array
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
|
||||
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]>
|
||||
where
|
||||
|
|
|
@ -1314,6 +1314,7 @@ extern "rust-intrinsic" {
|
|||
/// The stabilized version of this intrinsic is
|
||||
/// [`std::pointer::offset`](../../std/primitive.pointer.html#method.offset).
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
|
||||
/// Calculates the offset from a pointer, potentially wrapping.
|
||||
|
@ -1331,6 +1332,7 @@ extern "rust-intrinsic" {
|
|||
/// The stabilized version of this intrinsic is
|
||||
/// [`std::pointer::wrapping_offset`](../../std/primitive.pointer.html#method.wrapping_offset).
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
|
||||
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::char;
|
||||
use crate::convert::TryFrom;
|
||||
use crate::mem;
|
||||
use crate::ops::{self, Add, Sub, Try};
|
||||
|
@ -400,6 +401,73 @@ step_integer_impls! {
|
|||
wider than usize: [u32 i32], [u64 i64], [u128 i128];
|
||||
}
|
||||
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for char {
|
||||
#[inline]
|
||||
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
|
||||
let start = start as u32;
|
||||
let end = end as u32;
|
||||
if start <= end {
|
||||
let count = end - start;
|
||||
if start < 0xD800 && 0xE000 <= end {
|
||||
usize::try_from(count - 0x800).ok()
|
||||
} else {
|
||||
usize::try_from(count).ok()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn forward_checked(start: char, count: usize) -> Option<char> {
|
||||
let start = start as u32;
|
||||
let mut res = Step::forward_checked(start, count)?;
|
||||
if start < 0xD800 && 0xD800 <= res {
|
||||
res = Step::forward_checked(res, 0x800)?;
|
||||
}
|
||||
if res <= char::MAX as u32 {
|
||||
// SAFETY: res is a valid unicode scalar
|
||||
// (below 0x110000 and not in 0xD800..0xE000)
|
||||
Some(unsafe { char::from_u32_unchecked(res) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: char, count: usize) -> Option<char> {
|
||||
let start = start as u32;
|
||||
let mut res = Step::backward_checked(start, count)?;
|
||||
if start >= 0xE000 && 0xE000 > res {
|
||||
res = Step::backward_checked(res, 0x800)?;
|
||||
}
|
||||
// SAFETY: res is a valid unicode scalar
|
||||
// (below 0x110000 and not in 0xD800..0xE000)
|
||||
Some(unsafe { char::from_u32_unchecked(res) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn forward_unchecked(start: char, count: usize) -> char {
|
||||
let start = start as u32;
|
||||
let mut res = Step::forward_unchecked(start, count);
|
||||
if start < 0xD800 && 0xD800 <= res {
|
||||
res = Step::forward_unchecked(res, 0x800);
|
||||
}
|
||||
char::from_u32_unchecked(res)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn backward_unchecked(start: char, count: usize) -> char {
|
||||
let start = start as u32;
|
||||
let mut res = Step::backward_unchecked(start, count);
|
||||
if start >= 0xE000 && 0xE000 > res {
|
||||
res = Step::backward_unchecked(res, 0x800);
|
||||
}
|
||||
char::from_u32_unchecked(res)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! range_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -582,7 +650,11 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
|||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
let n = Step::forward(self.start.clone(), 1);
|
||||
// SAFETY: just checked precondition
|
||||
// We use the unchecked version here, because
|
||||
// otherwise `for _ in '\0'..=char::MAX`
|
||||
// does not successfully remove panicking code.
|
||||
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
|
||||
mem::replace(&mut self.start, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#![feature(const_panic)]
|
||||
#![feature(const_fn_union)]
|
||||
#![feature(const_generics)]
|
||||
#![feature(const_ptr_offset)]
|
||||
#![feature(const_ptr_offset_from)]
|
||||
#![feature(const_result)]
|
||||
#![feature(const_slice_from_raw_parts)]
|
||||
|
|
|
@ -151,8 +151,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn offset(self, count: isize) -> *const T
|
||||
pub const unsafe fn offset(self, count: isize) -> *const T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -210,8 +211,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset(self, count: isize) -> *const T
|
||||
pub const fn wrapping_offset(self, count: isize) -> *const T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -393,8 +395,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn add(self, count: usize) -> Self
|
||||
pub const unsafe fn add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -455,8 +458,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn sub(self, count: usize) -> Self
|
||||
pub const unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -511,8 +515,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_add(self, count: usize) -> Self
|
||||
pub const fn wrapping_add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -567,8 +572,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_sub(self, count: usize) -> Self
|
||||
pub const fn wrapping_sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
|
@ -145,8 +145,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn offset(self, count: isize) -> *mut T
|
||||
pub const unsafe fn offset(self, count: isize) -> *mut T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -203,8 +204,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset(self, count: isize) -> *mut T
|
||||
pub const fn wrapping_offset(self, count: isize) -> *mut T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -439,8 +441,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn add(self, count: usize) -> Self
|
||||
pub const unsafe fn add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -501,8 +504,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn sub(self, count: usize) -> Self
|
||||
pub const unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -557,8 +561,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_add(self, count: usize) -> Self
|
||||
pub const fn wrapping_add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -613,8 +618,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_sub(self, count: usize) -> Self
|
||||
pub const fn wrapping_sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
|
@ -1956,6 +1956,18 @@ fn test_range() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_range() {
|
||||
use std::char;
|
||||
assert!(('\0'..=char::MAX).eq((0..=char::MAX as u32).filter_map(char::from_u32)));
|
||||
assert!(('\0'..=char::MAX).rev().eq((0..=char::MAX as u32).filter_map(char::from_u32).rev()));
|
||||
|
||||
assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2);
|
||||
assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2)));
|
||||
assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1);
|
||||
assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_exhaustion() {
|
||||
let mut r = 10..10;
|
||||
|
|
|
@ -254,6 +254,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
]);
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
|
||||
InlineAsmArch::Nvptx64 => {}
|
||||
}
|
||||
}
|
||||
if !options.contains(InlineAsmOptions::NOMEM) {
|
||||
|
@ -410,6 +411,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String {
|
|||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
|
||||
|
@ -452,6 +456,7 @@ fn modifier_to_llvm(
|
|||
modifier
|
||||
}
|
||||
}
|
||||
InlineAsmRegClass::Nvptx(_) => None,
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
|
||||
|
@ -502,6 +507,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
|
|||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
|
||||
cx.type_vector(cx.type_i64(), 2)
|
||||
}
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
|
||||
|
|
|
@ -1194,9 +1194,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
|
|||
};
|
||||
|
||||
// Adjust the output kind to target capabilities.
|
||||
let pic_exe_supported = sess.target.target.options.position_independent_executables;
|
||||
let static_pic_exe_supported = false; // FIXME: Add this option to target specs.
|
||||
let static_dylib_supported = sess.target.target.options.crt_static_allows_dylibs;
|
||||
let opts = &sess.target.target.options;
|
||||
let pic_exe_supported = opts.position_independent_executables;
|
||||
let static_pic_exe_supported = opts.static_position_independent_executables;
|
||||
let static_dylib_supported = opts.crt_static_allows_dylibs;
|
||||
match kind {
|
||||
LinkOutputKind::DynamicPicExe if !pic_exe_supported => LinkOutputKind::DynamicNoPicExe,
|
||||
LinkOutputKind::StaticPicExe if !static_pic_exe_supported => LinkOutputKind::StaticNoPicExe,
|
||||
|
@ -1580,16 +1581,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
|||
}
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// FIXME: Support `StaticPicExe` correctly.
|
||||
match link_output_kind {
|
||||
LinkOutputKind::DynamicPicExe | LinkOutputKind::StaticPicExe => {
|
||||
cmd.position_independent_executable()
|
||||
}
|
||||
LinkOutputKind::DynamicNoPicExe | LinkOutputKind::StaticNoPicExe => {
|
||||
cmd.no_position_independent_executable()
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
cmd.set_output_kind(link_output_kind, out_filename);
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
add_relro_args(cmd, sess);
|
||||
|
@ -1618,17 +1610,6 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
|||
tmpdir,
|
||||
);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
// FIXME: Merge with the previous `link_output_kind` match,
|
||||
// and support `StaticPicExe` and `StaticDylib` correctly.
|
||||
match link_output_kind {
|
||||
LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {
|
||||
cmd.build_static_executable()
|
||||
}
|
||||
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => cmd.build_dylib(out_filename),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.opts.cg.profile_generate.enabled() {
|
||||
cmd.pgo_gen();
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc_serialize::{json, Encoder};
|
|||
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::{LinkerFlavor, LldFlavor};
|
||||
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
|
||||
|
||||
/// Disables non-English messages from localized linkers.
|
||||
/// Such messages may cause issues with text encoding on Windows (#35785)
|
||||
|
@ -101,6 +101,7 @@ impl LinkerInfo {
|
|||
/// MSVC linker (e.g., `link.exe`) is being used.
|
||||
pub trait Linker {
|
||||
fn cmd(&mut self) -> &mut Command;
|
||||
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
|
||||
fn link_dylib(&mut self, lib: Symbol);
|
||||
fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
|
||||
fn link_framework(&mut self, framework: Symbol);
|
||||
|
@ -113,8 +114,6 @@ pub trait Linker {
|
|||
fn output_filename(&mut self, path: &Path);
|
||||
fn add_object(&mut self, path: &Path);
|
||||
fn gc_sections(&mut self, keep_metadata: bool);
|
||||
fn position_independent_executable(&mut self);
|
||||
fn no_position_independent_executable(&mut self);
|
||||
fn full_relro(&mut self);
|
||||
fn partial_relro(&mut self);
|
||||
fn no_relro(&mut self);
|
||||
|
@ -124,8 +123,6 @@ pub trait Linker {
|
|||
fn debuginfo(&mut self, strip: Strip);
|
||||
fn no_crt_objects(&mut self);
|
||||
fn no_default_libraries(&mut self);
|
||||
fn build_dylib(&mut self, out_filename: &Path);
|
||||
fn build_static_executable(&mut self);
|
||||
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
|
||||
fn subsystem(&mut self, subsystem: &str);
|
||||
fn group_start(&mut self);
|
||||
|
@ -232,12 +229,94 @@ impl<'a> GccLinker<'a> {
|
|||
let target_cpu = self.target_cpu;
|
||||
self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu));
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, out_filename: &Path) {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if self.sess.target.target.options.is_like_osx {
|
||||
self.cmd.arg("-dynamiclib");
|
||||
self.linker_arg("-dylib");
|
||||
|
||||
// Note that the `osx_rpath_install_name` option here is a hack
|
||||
// purely to support rustbuild right now, we should get a more
|
||||
// principled solution at some point to force the compiler to pass
|
||||
// the right `-Wl,-install_name` with an `@rpath` in it.
|
||||
if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
|
||||
self.linker_arg("-install_name");
|
||||
let mut v = OsString::from("@rpath/");
|
||||
v.push(out_filename.file_name().unwrap());
|
||||
self.linker_arg(&v);
|
||||
}
|
||||
} else {
|
||||
self.cmd.arg("-shared");
|
||||
if self.sess.target.target.options.is_like_windows {
|
||||
// The output filename already contains `dll_suffix` so
|
||||
// the resulting import library will have a name in the
|
||||
// form of libfoo.dll.a
|
||||
let implib_name =
|
||||
out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
|
||||
format!(
|
||||
"{}{}{}",
|
||||
self.sess.target.target.options.staticlib_prefix,
|
||||
file,
|
||||
self.sess.target.target.options.staticlib_suffix
|
||||
)
|
||||
});
|
||||
if let Some(implib_name) = implib_name {
|
||||
let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
|
||||
if let Some(implib) = implib {
|
||||
self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Linker for GccLinker<'a> {
|
||||
fn cmd(&mut self) -> &mut Command {
|
||||
&mut self.cmd
|
||||
}
|
||||
|
||||
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
|
||||
match output_kind {
|
||||
LinkOutputKind::DynamicNoPicExe => {
|
||||
if !self.is_ld {
|
||||
self.cmd.arg("-no-pie");
|
||||
}
|
||||
}
|
||||
LinkOutputKind::DynamicPicExe => {
|
||||
// `-pie` works for both gcc wrapper and ld.
|
||||
self.cmd.arg("-pie");
|
||||
}
|
||||
LinkOutputKind::StaticNoPicExe => {
|
||||
// `-static` works for both gcc wrapper and ld.
|
||||
self.cmd.arg("-static");
|
||||
if !self.is_ld {
|
||||
self.cmd.arg("-no-pie");
|
||||
}
|
||||
}
|
||||
LinkOutputKind::StaticPicExe => {
|
||||
if !self.is_ld {
|
||||
// Note that combination `-static -pie` doesn't work as expected
|
||||
// for the gcc wrapper, `-static` in that case suppresses `-pie`.
|
||||
self.cmd.arg("-static-pie");
|
||||
} else {
|
||||
// `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
|
||||
// a static pie, but currently passed because gcc and clang pass them.
|
||||
// The former suppresses the `INTERP` ELF header specifying dynamic linker,
|
||||
// which is otherwise implicitly injected by ld (but not lld).
|
||||
// The latter doesn't change anything, only ensures that everything is pic.
|
||||
self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
|
||||
}
|
||||
}
|
||||
LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
|
||||
LinkOutputKind::StaticDylib => {
|
||||
self.cmd.arg("-static");
|
||||
self.build_dylib(out_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn link_dylib(&mut self, lib: Symbol) {
|
||||
self.hint_dynamic();
|
||||
self.cmd.arg(format!("-l{}", lib));
|
||||
|
@ -262,14 +341,6 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
fn add_object(&mut self, path: &Path) {
|
||||
self.cmd.arg(path);
|
||||
}
|
||||
fn position_independent_executable(&mut self) {
|
||||
self.cmd.arg("-pie");
|
||||
}
|
||||
fn no_position_independent_executable(&mut self) {
|
||||
if !self.is_ld {
|
||||
self.cmd.arg("-no-pie");
|
||||
}
|
||||
}
|
||||
fn full_relro(&mut self) {
|
||||
self.linker_arg("-zrelro");
|
||||
self.linker_arg("-znow");
|
||||
|
@ -280,9 +351,6 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
fn no_relro(&mut self) {
|
||||
self.linker_arg("-znorelro");
|
||||
}
|
||||
fn build_static_executable(&mut self) {
|
||||
self.cmd.arg("-static");
|
||||
}
|
||||
|
||||
fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
|
||||
self.hint_dynamic();
|
||||
|
@ -418,47 +486,6 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, out_filename: &Path) {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if self.sess.target.target.options.is_like_osx {
|
||||
self.cmd.arg("-dynamiclib");
|
||||
self.linker_arg("-dylib");
|
||||
|
||||
// Note that the `osx_rpath_install_name` option here is a hack
|
||||
// purely to support rustbuild right now, we should get a more
|
||||
// principled solution at some point to force the compiler to pass
|
||||
// the right `-Wl,-install_name` with an `@rpath` in it.
|
||||
if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
|
||||
self.linker_arg("-install_name");
|
||||
let mut v = OsString::from("@rpath/");
|
||||
v.push(out_filename.file_name().unwrap());
|
||||
self.linker_arg(&v);
|
||||
}
|
||||
} else {
|
||||
self.cmd.arg("-shared");
|
||||
if self.sess.target.target.options.is_like_windows {
|
||||
// The output filename already contains `dll_suffix` so
|
||||
// the resulting import library will have a name in the
|
||||
// form of libfoo.dll.a
|
||||
let implib_name =
|
||||
out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
|
||||
format!(
|
||||
"{}{}{}",
|
||||
self.sess.target.target.options.staticlib_prefix,
|
||||
file,
|
||||
self.sess.target.target.options.staticlib_suffix
|
||||
)
|
||||
});
|
||||
if let Some(implib_name) = implib_name {
|
||||
let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
|
||||
if let Some(implib) = implib {
|
||||
self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
|
||||
// Symbol visibility in object files typically takes care of this.
|
||||
if crate_type == CrateType::Executable
|
||||
|
@ -582,6 +609,22 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
fn cmd(&mut self) -> &mut Command {
|
||||
&mut self.cmd
|
||||
}
|
||||
|
||||
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
|
||||
match output_kind {
|
||||
LinkOutputKind::DynamicNoPicExe
|
||||
| LinkOutputKind::DynamicPicExe
|
||||
| LinkOutputKind::StaticNoPicExe
|
||||
| LinkOutputKind::StaticPicExe => {}
|
||||
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
|
||||
self.cmd.arg("/DLL");
|
||||
let mut arg: OsString = "/IMPLIB:".into();
|
||||
arg.push(out_filename.with_extension("dll.lib"));
|
||||
self.cmd.arg(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn link_rlib(&mut self, lib: &Path) {
|
||||
self.cmd.arg(lib);
|
||||
}
|
||||
|
@ -589,17 +632,6 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
self.cmd.arg(path);
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, out_filename: &Path) {
|
||||
self.cmd.arg("/DLL");
|
||||
let mut arg: OsString = "/IMPLIB:".into();
|
||||
arg.push(out_filename.with_extension("dll.lib"));
|
||||
self.cmd.arg(arg);
|
||||
}
|
||||
|
||||
fn build_static_executable(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn gc_sections(&mut self, _keep_metadata: bool) {
|
||||
// MSVC's ICF (Identical COMDAT Folding) link optimization is
|
||||
// slow for Rust and thus we disable it by default when not in
|
||||
|
@ -632,14 +664,6 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
self.cmd.arg(&format!("{}.lib", lib));
|
||||
}
|
||||
|
||||
fn position_independent_executable(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn no_position_independent_executable(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn full_relro(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
@ -817,6 +841,9 @@ impl<'a> Linker for EmLinker<'a> {
|
|||
fn cmd(&mut self) -> &mut Command {
|
||||
&mut self.cmd
|
||||
}
|
||||
|
||||
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
|
||||
|
||||
fn include_path(&mut self, path: &Path) {
|
||||
self.cmd.arg("-L").arg(path);
|
||||
}
|
||||
|
@ -856,14 +883,6 @@ impl<'a> Linker for EmLinker<'a> {
|
|||
self.add_object(lib);
|
||||
}
|
||||
|
||||
fn position_independent_executable(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn no_position_independent_executable(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn full_relro(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
@ -925,14 +944,6 @@ impl<'a> Linker for EmLinker<'a> {
|
|||
self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, _out_filename: &Path) {
|
||||
bug!("building dynamic library is unsupported on Emscripten")
|
||||
}
|
||||
|
||||
fn build_static_executable(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
|
||||
let symbols = &self.info.exports[&crate_type];
|
||||
|
||||
|
@ -1031,6 +1042,18 @@ impl<'a> Linker for WasmLd<'a> {
|
|||
&mut self.cmd
|
||||
}
|
||||
|
||||
fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
|
||||
match output_kind {
|
||||
LinkOutputKind::DynamicNoPicExe
|
||||
| LinkOutputKind::DynamicPicExe
|
||||
| LinkOutputKind::StaticNoPicExe
|
||||
| LinkOutputKind::StaticPicExe => {}
|
||||
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
|
||||
self.cmd.arg("--no-entry");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn link_dylib(&mut self, lib: Symbol) {
|
||||
self.cmd.arg("-l").sym_arg(lib);
|
||||
}
|
||||
|
@ -1059,16 +1082,12 @@ impl<'a> Linker for WasmLd<'a> {
|
|||
self.cmd.arg(path);
|
||||
}
|
||||
|
||||
fn position_independent_executable(&mut self) {}
|
||||
|
||||
fn full_relro(&mut self) {}
|
||||
|
||||
fn partial_relro(&mut self) {}
|
||||
|
||||
fn no_relro(&mut self) {}
|
||||
|
||||
fn build_static_executable(&mut self) {}
|
||||
|
||||
fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
|
||||
self.cmd.arg("-l").sym_arg(lib);
|
||||
}
|
||||
|
@ -1124,10 +1143,6 @@ impl<'a> Linker for WasmLd<'a> {
|
|||
|
||||
fn no_default_libraries(&mut self) {}
|
||||
|
||||
fn build_dylib(&mut self, _out_filename: &Path) {
|
||||
self.cmd.arg("--no-entry");
|
||||
}
|
||||
|
||||
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
|
||||
for sym in self.info.exports[&crate_type].iter() {
|
||||
self.cmd.arg("--export").arg(&sym);
|
||||
|
@ -1143,8 +1158,6 @@ impl<'a> Linker for WasmLd<'a> {
|
|||
|
||||
fn subsystem(&mut self, _subsystem: &str) {}
|
||||
|
||||
fn no_position_independent_executable(&mut self) {}
|
||||
|
||||
fn finalize(&mut self) {}
|
||||
|
||||
// Not needed for now with LLD
|
||||
|
@ -1207,6 +1220,8 @@ impl<'a> Linker for PtxLinker<'a> {
|
|||
&mut self.cmd
|
||||
}
|
||||
|
||||
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
|
||||
|
||||
fn link_rlib(&mut self, path: &Path) {
|
||||
self.cmd.arg("--rlib").arg(path);
|
||||
}
|
||||
|
@ -1273,16 +1288,12 @@ impl<'a> Linker for PtxLinker<'a> {
|
|||
panic!("frameworks not supported")
|
||||
}
|
||||
|
||||
fn position_independent_executable(&mut self) {}
|
||||
|
||||
fn full_relro(&mut self) {}
|
||||
|
||||
fn partial_relro(&mut self) {}
|
||||
|
||||
fn no_relro(&mut self) {}
|
||||
|
||||
fn build_static_executable(&mut self) {}
|
||||
|
||||
fn gc_sections(&mut self, _keep_metadata: bool) {}
|
||||
|
||||
fn pgo_gen(&mut self) {}
|
||||
|
@ -1295,14 +1306,10 @@ impl<'a> Linker for PtxLinker<'a> {
|
|||
self.sess.warn("Windows Control Flow Guard is not supported by this linker.");
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, _out_filename: &Path) {}
|
||||
|
||||
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
|
||||
|
||||
fn subsystem(&mut self, _subsystem: &str) {}
|
||||
|
||||
fn no_position_independent_executable(&mut self) {}
|
||||
|
||||
fn group_start(&mut self) {}
|
||||
|
||||
fn group_end(&mut self) {}
|
||||
|
|
|
@ -193,9 +193,18 @@ impl Diagnostic {
|
|||
expected_extra: &dyn fmt::Display,
|
||||
found_extra: &dyn fmt::Display,
|
||||
) -> &mut Self {
|
||||
let expected_label = format!("expected {}", expected_label);
|
||||
|
||||
let found_label = format!("found {}", found_label);
|
||||
let expected_label = expected_label.to_string();
|
||||
let expected_label = if expected_label.is_empty() {
|
||||
"expected".to_string()
|
||||
} else {
|
||||
format!("expected {}", expected_label)
|
||||
};
|
||||
let found_label = found_label.to_string();
|
||||
let found_label = if found_label.is_empty() {
|
||||
"found".to_string()
|
||||
} else {
|
||||
format!("found {}", found_label)
|
||||
};
|
||||
let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
|
||||
(expected_label.len() - found_label.len(), 0)
|
||||
} else {
|
||||
|
|
|
@ -571,6 +571,9 @@ declare_features! (
|
|||
/// Allows the use of `#[ffi_const]` on foreign functions.
|
||||
(active, ffi_const, "1.45.0", Some(58328), None),
|
||||
|
||||
/// No longer treat an unsafe function as an unsafe block.
|
||||
(active, unsafe_block_in_unsafe_fn, "1.45.0", Some(71668), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
@ -987,12 +987,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn push_ty_ref<'tcx>(
|
||||
r: &ty::Region<'tcx>,
|
||||
region: &ty::Region<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
s: &mut DiagnosticStyledString,
|
||||
) {
|
||||
let mut r = r.to_string();
|
||||
let mut r = region.to_string();
|
||||
if r == "'_" {
|
||||
r.clear();
|
||||
} else {
|
||||
|
|
|
@ -2,11 +2,16 @@
|
|||
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||
use crate::infer::{Subtype, ValuePairs};
|
||||
use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs};
|
||||
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
|
||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
|
||||
|
@ -36,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
var_origin.span(),
|
||||
sub_expected_found.expected,
|
||||
sub_expected_found.found,
|
||||
self.tcx().def_span(*trait_item_def_id),
|
||||
*trait_item_def_id,
|
||||
);
|
||||
return Some(ErrorReported);
|
||||
}
|
||||
|
@ -47,14 +52,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) {
|
||||
fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
|
||||
let tcx = self.tcx();
|
||||
let trait_sp = self.tcx().def_span(trait_def_id);
|
||||
let mut err = self
|
||||
.tcx()
|
||||
.sess
|
||||
.struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
|
||||
err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found));
|
||||
err.span_label(sp, &format!("found {:?}", found));
|
||||
err.span_label(impl_sp, &format!("expected {:?}", expected));
|
||||
err.span_label(sp, &format!("found `{:?}`", found));
|
||||
err.span_label(trait_sp, &format!("expected `{:?}`", expected));
|
||||
|
||||
// Get the span of all the used type parameters in the method.
|
||||
let assoc_item = self.tcx().associated_item(trait_def_id);
|
||||
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
|
||||
match assoc_item.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
let hir = self.tcx().hir();
|
||||
if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| hir.as_local_hir_id(id))
|
||||
{
|
||||
if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
|
||||
visitor.visit_fn_decl(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut type_param_span: MultiSpan =
|
||||
visitor.types.iter().cloned().collect::<Vec<_>>().into();
|
||||
for &span in &visitor.types {
|
||||
type_param_span.push_span_label(
|
||||
span,
|
||||
"consider borrowing this type parameter in the trait".to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((expected, found)) = tcx
|
||||
.infer_ctxt()
|
||||
.enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found }))
|
||||
{
|
||||
// Highlighted the differences when showing the "expected/found" note.
|
||||
err.note_expected_found(&"", expected, &"", found);
|
||||
} else {
|
||||
// This fallback shouldn't be necessary, but let's keep it in just in case.
|
||||
err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found));
|
||||
}
|
||||
err.span_help(
|
||||
type_param_span,
|
||||
"the lifetime requirements from the `impl` do not correspond to the requirements in \
|
||||
the `trait`",
|
||||
);
|
||||
if visitor.types.is_empty() {
|
||||
err.help(
|
||||
"verify the lifetime relationships in the `trait` and `impl` between the `self` \
|
||||
argument, the other inputs and its output",
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeParamSpanVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
types: Vec<Span>,
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
||||
type Map = rustc_middle::hir::map::Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
|
||||
hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
|
||||
match arg.kind {
|
||||
hir::TyKind::Rptr(_, ref mut_ty) => {
|
||||
// We don't want to suggest looking into borrowing `&T` or `&Self`.
|
||||
hir::intravisit::walk_ty(self, mut_ty.ty);
|
||||
return;
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
|
||||
[segment]
|
||||
if segment
|
||||
.res
|
||||
.map(|res| match res {
|
||||
Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
|
||||
_ => false,
|
||||
})
|
||||
.unwrap_or(false) =>
|
||||
{
|
||||
self.types.push(path.span);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
hir::intravisit::walk_ty(self, arg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,11 +14,11 @@ use rustc_middle::lint::LintDiagnosticBuilder;
|
|||
use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::{builtin, Level, Lint};
|
||||
use rustc_session::lint::{builtin, Level, Lint, LintId};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::MultiSpan;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
|
||||
|
||||
use std::cmp;
|
||||
|
||||
|
@ -80,11 +80,13 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
let level = cmp::min(level, self.sets.lint_cap);
|
||||
|
||||
let lint_flag_val = Symbol::intern(lint_name);
|
||||
|
||||
let ids = match store.find_lints(&lint_name) {
|
||||
Ok(ids) => ids,
|
||||
Err(_) => continue, // errors handled in check_lint_name_cmdline above
|
||||
};
|
||||
for id in ids {
|
||||
self.check_gated_lint(id, DUMMY_SP);
|
||||
let src = LintSource::CommandLine(lint_flag_val);
|
||||
specs.insert(id, (level, src));
|
||||
}
|
||||
|
@ -213,6 +215,7 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
CheckLintNameResult::Ok(ids) => {
|
||||
let src = LintSource::Node(name, li.span(), reason);
|
||||
for id in ids {
|
||||
self.check_gated_lint(*id, attr.span);
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
}
|
||||
|
@ -383,6 +386,20 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
BuilderPush { prev, changed: prev != self.cur }
|
||||
}
|
||||
|
||||
fn check_gated_lint(&self, id: LintId, span: Span) {
|
||||
if id == LintId::of(builtin::UNSAFE_OP_IN_UNSAFE_FN)
|
||||
&& !self.sess.features_untracked().unsafe_block_in_unsafe_fn
|
||||
{
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::unsafe_block_in_unsafe_fn,
|
||||
span,
|
||||
"the `unsafe_op_in_unsafe_fn` lint is unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// Called after `push` when the scope of a set of attributes are exited.
|
||||
pub fn pop(&mut self, push: BuilderPush) {
|
||||
self.cur = push.prev;
|
||||
|
|
|
@ -598,3 +598,12 @@ pub fn truncate(value: u128, size: Size) -> u128 {
|
|||
// Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
|
||||
(value << shift) >> shift
|
||||
}
|
||||
|
||||
/// Computes the unsigned absolute value without wrapping or panicking.
|
||||
#[inline]
|
||||
pub fn uabs(value: i64) -> u64 {
|
||||
// The only tricky part here is if value == i64::MIN. In that case,
|
||||
// wrapping_abs() returns i64::MIN == -2^63. Casting this value to a u64
|
||||
// gives 2^63, the correct value.
|
||||
value.wrapping_abs() as u64
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{AllocId, InterpResult};
|
||||
use super::{uabs, AllocId, InterpResult};
|
||||
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_target::abi::{HasDataLayout, Size};
|
||||
|
@ -24,6 +24,12 @@ pub trait PointerArithmetic: HasDataLayout {
|
|||
u64::try_from(max_usize_plus_1 - 1).unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn machine_isize_min(&self) -> i64 {
|
||||
let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1);
|
||||
i64::try_from(-max_isize_plus_1).unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn machine_isize_max(&self) -> i64 {
|
||||
let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1);
|
||||
|
@ -42,21 +48,23 @@ pub trait PointerArithmetic: HasDataLayout {
|
|||
|
||||
#[inline]
|
||||
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
|
||||
// We do not need to check if i fits in a machine usize. If it doesn't,
|
||||
// either the wrapping_add will wrap or res will not fit in a pointer.
|
||||
let res = val.overflowing_add(i);
|
||||
self.truncate_to_ptr(res)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
|
||||
if i < 0 {
|
||||
// Trickery to ensure that `i64::MIN` works fine: compute `n = -i`.
|
||||
// This formula only works for true negative values; it overflows for zero!
|
||||
let n = u64::MAX - (i as u64) + 1;
|
||||
let res = val.overflowing_sub(n);
|
||||
self.truncate_to_ptr(res)
|
||||
// We need to make sure that i fits in a machine isize.
|
||||
let n = uabs(i);
|
||||
if i >= 0 {
|
||||
let (val, over) = self.overflowing_offset(val, n);
|
||||
(val, over || i > self.machine_isize_max())
|
||||
} else {
|
||||
// `i >= 0`, so the cast is safe.
|
||||
self.overflowing_offset(val, i as u64)
|
||||
let res = val.overflowing_sub(n);
|
||||
let (val, over) = self.truncate_to_ptr(res);
|
||||
(val, over || i < self.machine_isize_min())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -408,7 +408,7 @@ impl<'tcx> Body<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub enum Safety {
|
||||
Safe,
|
||||
/// Unsafe because of a PushUnsafeBlock
|
||||
|
|
|
@ -15,15 +15,27 @@ use super::{Field, SourceInfo};
|
|||
|
||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub enum UnsafetyViolationKind {
|
||||
/// Only permitted in regular `fn`s, prohibitted in `const fn`s.
|
||||
General,
|
||||
/// Permitted both in `const fn`s and regular `fn`s.
|
||||
GeneralAndConstFn,
|
||||
BorrowPacked(hir::HirId),
|
||||
/// Borrow of packed field.
|
||||
/// Has to be handled as a lint for backwards compatibility.
|
||||
BorrowPacked,
|
||||
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
|
||||
/// Has to be handled as a lint for backwards compatibility.
|
||||
/// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`.
|
||||
UnsafeFn,
|
||||
/// Borrow of packed field in an `unsafe fn` but outside an `unsafe` block.
|
||||
/// Has to be handled as a lint for backwards compatibility.
|
||||
/// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`.
|
||||
UnsafeFnBorrowPacked,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub struct UnsafetyViolation {
|
||||
pub source_info: SourceInfo,
|
||||
pub lint_root: hir::HirId,
|
||||
pub description: Symbol,
|
||||
pub details: Symbol,
|
||||
pub kind: UnsafetyViolationKind,
|
||||
|
|
|
@ -214,7 +214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let generics = tcx.generics_of(self.mir_def_id);
|
||||
let param = generics.type_param(¶m_ty, tcx);
|
||||
if let Some(generics) =
|
||||
tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id))
|
||||
tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id.to_def_id()))
|
||||
{
|
||||
suggest_constraining_type_param(
|
||||
tcx,
|
||||
|
@ -865,49 +865,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
format!("`{}` would have to be valid for `{}`...", name, region_name),
|
||||
);
|
||||
|
||||
if let Some(def_id) = self.mir_def_id.as_local() {
|
||||
let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id);
|
||||
err.span_label(
|
||||
drop_span,
|
||||
format!(
|
||||
"...but `{}` will be dropped here, when the {} returns",
|
||||
name,
|
||||
self.infcx
|
||||
.tcx
|
||||
.hir()
|
||||
.opt_name(fn_hir_id)
|
||||
.map(|name| format!("function `{}`", name))
|
||||
.unwrap_or_else(|| {
|
||||
match &self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck_tables_of(def_id)
|
||||
.node_type(fn_hir_id)
|
||||
.kind
|
||||
{
|
||||
ty::Closure(..) => "enclosing closure",
|
||||
ty::Generator(..) => "enclosing generator",
|
||||
kind => bug!("expected closure or generator, found {:?}", kind),
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
),
|
||||
);
|
||||
let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
|
||||
err.span_label(
|
||||
drop_span,
|
||||
format!(
|
||||
"...but `{}` will be dropped here, when the {} returns",
|
||||
name,
|
||||
self.infcx
|
||||
.tcx
|
||||
.hir()
|
||||
.opt_name(fn_hir_id)
|
||||
.map(|name| format!("function `{}`", name))
|
||||
.unwrap_or_else(|| {
|
||||
match &self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck_tables_of(self.mir_def_id)
|
||||
.node_type(fn_hir_id)
|
||||
.kind
|
||||
{
|
||||
ty::Closure(..) => "enclosing closure",
|
||||
ty::Generator(..) => "enclosing generator",
|
||||
kind => bug!("expected closure or generator, found {:?}", kind),
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
),
|
||||
);
|
||||
|
||||
err.note(
|
||||
"functions cannot return a borrow to data owned within the function's scope, \
|
||||
functions can only return borrows to data passed as arguments",
|
||||
);
|
||||
err.note(
|
||||
"to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
|
||||
references-and-borrowing.html#dangling-references>",
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
drop_span,
|
||||
format!("...but `{}` dropped here while still borrowed", name),
|
||||
);
|
||||
}
|
||||
err.note(
|
||||
"functions cannot return a borrow to data owned within the function's scope, \
|
||||
functions can only return borrows to data passed as arguments",
|
||||
);
|
||||
err.note(
|
||||
"to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
|
||||
references-and-borrowing.html#dangling-references>",
|
||||
);
|
||||
|
||||
if let BorrowExplanation::MustBeValidFor { .. } = explanation {
|
||||
} else {
|
||||
|
@ -1237,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
) -> DiagnosticBuilder<'cx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let (_, escapes_from) = tcx.article_and_description(self.mir_def_id);
|
||||
let (_, escapes_from) = tcx.article_and_description(self.mir_def_id.to_def_id());
|
||||
|
||||
let mut err =
|
||||
borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
|
||||
|
@ -1572,14 +1565,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
// Define a fallback for when we can't match a closure.
|
||||
let fallback = || {
|
||||
let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
|
||||
let is_closure = self.infcx.tcx.is_closure(self.mir_def_id.to_def_id());
|
||||
if is_closure {
|
||||
None
|
||||
} else {
|
||||
let ty = self.infcx.tcx.type_of(self.mir_def_id);
|
||||
match ty.kind {
|
||||
ty::FnDef(_, _) | ty::FnPtr(_) => self
|
||||
.annotate_fn_sig(self.mir_def_id, self.infcx.tcx.fn_sig(self.mir_def_id)),
|
||||
ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
|
||||
self.mir_def_id.to_def_id(),
|
||||
self.infcx.tcx.fn_sig(self.mir_def_id),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -331,7 +331,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
self.cannot_move_out_of_interior_noncopy(span, ty, None)
|
||||
}
|
||||
ty::Closure(def_id, closure_substs)
|
||||
if def_id == self.mir_def_id && upvar_field.is_some() =>
|
||||
if def_id.as_local() == Some(self.mir_def_id) && upvar_field.is_some() =>
|
||||
{
|
||||
let closure_kind_ty = closure_substs.as_closure().kind_ty();
|
||||
let closure_kind = closure_kind_ty.to_opt_closure_kind();
|
||||
|
|
|
@ -492,7 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
err.span_label(sp, format!("cannot {}", act));
|
||||
|
||||
let hir = self.infcx.tcx.hir();
|
||||
let closure_id = hir.as_local_hir_id(self.mir_def_id.expect_local());
|
||||
let closure_id = hir.as_local_hir_id(self.mir_def_id);
|
||||
let fn_call_id = hir.get_parent_node(closure_id);
|
||||
let node = hir.get(fn_call_id);
|
||||
let item_id = hir.get_parent_item(fn_call_id);
|
||||
|
|
|
@ -498,7 +498,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let mut diag =
|
||||
self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
|
||||
|
||||
let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id);
|
||||
let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id.to_def_id());
|
||||
|
||||
let fr_name = self.give_region_a_name(*fr).unwrap();
|
||||
fr_name.highlight_region_name(&mut diag);
|
||||
|
|
|
@ -237,8 +237,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
ty::BoundRegion::BrEnv => {
|
||||
let mir_hir_id =
|
||||
self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.expect_local());
|
||||
let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
|
||||
let def_ty = self.regioncx.universal_regions().defining_ty;
|
||||
|
||||
if let DefiningTy::Closure(_, substs) = def_ty {
|
||||
|
@ -323,7 +322,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
argument_ty: Ty<'tcx>,
|
||||
argument_index: usize,
|
||||
) -> Option<RegionName> {
|
||||
let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.as_local()?);
|
||||
let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
|
||||
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
|
||||
let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
|
||||
match argument_hir_ty.kind {
|
||||
|
@ -634,7 +633,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
||||
let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0;
|
||||
|
||||
let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local());
|
||||
let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id);
|
||||
|
||||
let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) {
|
||||
hir::Node::Expr(hir::Expr {
|
||||
|
@ -686,7 +685,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
||||
let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0;
|
||||
|
||||
let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local());
|
||||
let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id);
|
||||
|
||||
let yield_span = match tcx.hir().get(mir_hir_id) {
|
||||
hir::Node::Expr(hir::Expr {
|
||||
|
|
|
@ -4,10 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{
|
||||
def_id::{DefId, LocalDefId},
|
||||
HirId, Node,
|
||||
};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::{HirId, Node};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
|
@ -174,7 +172,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
let mut body = input_body.clone();
|
||||
let mut promoted = input_promoted.clone();
|
||||
let free_regions =
|
||||
nll::replace_regions_in_mir(infcx, def_id.to_def_id(), param_env, &mut body, &mut promoted);
|
||||
nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
|
||||
let body = &body; // no further changes
|
||||
|
||||
let location_table = &LocationTable::new(&body);
|
||||
|
@ -275,7 +273,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
let mut promoted_mbcx = MirBorrowckCtxt {
|
||||
infcx,
|
||||
body: promoted_body,
|
||||
mir_def_id: def_id.to_def_id(),
|
||||
mir_def_id: def_id,
|
||||
move_data: &move_data,
|
||||
location_table: &LocationTable::new(promoted_body),
|
||||
movable_generator,
|
||||
|
@ -307,7 +305,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
let mut mbcx = MirBorrowckCtxt {
|
||||
infcx,
|
||||
body,
|
||||
mir_def_id: def_id.to_def_id(),
|
||||
mir_def_id: def_id,
|
||||
move_data: &mdpe.move_data,
|
||||
location_table,
|
||||
movable_generator,
|
||||
|
@ -459,7 +457,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
crate struct MirBorrowckCtxt<'cx, 'tcx> {
|
||||
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
body: &'cx Body<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
mir_def_id: LocalDefId,
|
||||
move_data: &'cx MoveData<'tcx>,
|
||||
|
||||
/// Map from MIR `Location` to `LocationIndex`; created
|
||||
|
|
|
@ -58,7 +58,7 @@ crate struct NllOutput<'tcx> {
|
|||
/// `compute_regions`.
|
||||
pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
|
||||
infcx: &InferCtxt<'cx, 'tcx>,
|
||||
def_id: DefId,
|
||||
def_id: LocalDefId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &mut Body<'tcx>,
|
||||
promoted: &mut IndexVec<Promoted, Body<'tcx>>,
|
||||
|
@ -66,12 +66,12 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
|
|||
debug!("replace_regions_in_mir(def_id={:?})", def_id);
|
||||
|
||||
// Compute named region information. This also renumbers the inputs/outputs.
|
||||
let universal_regions = UniversalRegions::new(infcx, def_id.expect_local(), param_env);
|
||||
let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
|
||||
|
||||
// Replace all remaining regions with fresh inference variables.
|
||||
renumber::renumber_mir(infcx, body, promoted);
|
||||
|
||||
let source = MirSource::item(def_id);
|
||||
let source = MirSource::item(def_id.to_def_id());
|
||||
mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
|
||||
|
||||
universal_regions
|
||||
|
|
|
@ -2,19 +2,21 @@
|
|||
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
|
||||
//! and miri.
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::{
|
||||
self,
|
||||
interpret::{ConstValue, GlobalId, InterpResult, Scalar},
|
||||
interpret::{uabs, ConstValue, GlobalId, InterpResult, Scalar},
|
||||
BinOp,
|
||||
};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
|
||||
|
||||
use super::{ImmTy, InterpCx, Machine, OpTy, PlaceTy};
|
||||
use super::{CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy};
|
||||
|
||||
mod caller_location;
|
||||
mod type_name;
|
||||
|
@ -279,7 +281,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let result = Scalar::from_uint(truncated_bits, layout.size);
|
||||
self.write_scalar(result, dest)?;
|
||||
}
|
||||
sym::offset => {
|
||||
let ptr = self.read_scalar(args[0])?.not_undef()?;
|
||||
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
|
||||
let pointee_ty = substs.type_at(0);
|
||||
|
||||
let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
|
||||
self.write_scalar(offset_ptr, dest)?;
|
||||
}
|
||||
sym::arith_offset => {
|
||||
let ptr = self.read_scalar(args[0])?.not_undef()?;
|
||||
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
|
||||
let pointee_ty = substs.type_at(0);
|
||||
|
||||
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
|
||||
let offset_bytes = offset_count.wrapping_mul(pointee_size);
|
||||
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
|
||||
self.write_scalar(offset_ptr, dest)?;
|
||||
}
|
||||
sym::ptr_offset_from => {
|
||||
let a = self.read_immediate(args[0])?.to_scalar()?;
|
||||
let b = self.read_immediate(args[1])?.to_scalar()?;
|
||||
|
@ -409,4 +428,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// `Rem` says this is all right, so we can let `Div` do its job.
|
||||
self.binop_ignore_overflow(BinOp::Div, a, b, dest)
|
||||
}
|
||||
|
||||
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
|
||||
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
|
||||
/// 0, so offset-by-0 (and only 0) is okay -- except that NULL cannot be offset by _any_ value.
|
||||
pub fn ptr_offset_inbounds(
|
||||
&self,
|
||||
ptr: Scalar<M::PointerTag>,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
offset_count: i64,
|
||||
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
||||
// We cannot overflow i64 as a type's size must be <= isize::MAX.
|
||||
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
|
||||
// The computed offset, in bytes, cannot overflow an isize.
|
||||
let offset_bytes =
|
||||
offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
|
||||
// The offset being in bounds cannot rely on "wrapping around" the address space.
|
||||
// So, first rule out overflows in the pointer arithmetic.
|
||||
let offset_ptr = ptr.ptr_signed_offset(offset_bytes, self)?;
|
||||
// ptr and offset_ptr must be in bounds of the same allocated object. This means all of the
|
||||
// memory between these pointers must be accessible. Note that we do not require the
|
||||
// pointers to be properly aligned (unlike a read/write operation).
|
||||
let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
|
||||
let size: u64 = uabs(offset_bytes);
|
||||
// This call handles checking for integer/NULL pointers.
|
||||
self.memory.check_ptr_access_align(
|
||||
min_ptr,
|
||||
Size::from_bytes(size),
|
||||
None,
|
||||
CheckInAllocMsg::InboundsTest,
|
||||
)?;
|
||||
Ok(offset_ptr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::hir_id::HirId;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
|
||||
|
@ -9,7 +10,8 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE};
|
||||
use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use std::ops::Bound;
|
||||
|
@ -202,25 +204,30 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root = self.body.source_scopes[source_info.scope]
|
||||
.local_data
|
||||
.as_ref()
|
||||
.assert_crate_local()
|
||||
.lint_root;
|
||||
self.require_unsafe(
|
||||
"borrow of packed field",
|
||||
"fields of packed structs might be misaligned: dereferencing a \
|
||||
misaligned pointer or even just creating a misaligned reference \
|
||||
is undefined behavior",
|
||||
UnsafetyViolationKind::BorrowPacked(lint_root),
|
||||
UnsafetyViolationKind::BorrowPacked,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (i, elem) in place.projection.iter().enumerate() {
|
||||
let proj_base = &place.projection[..i];
|
||||
let old_source_info = self.source_info;
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
|
||||
self.require_unsafe(
|
||||
"borrow of packed field",
|
||||
"fields of packed structs might be misaligned: dereferencing a \
|
||||
misaligned pointer or even just creating a misaligned reference \
|
||||
is undefined behavior",
|
||||
UnsafetyViolationKind::BorrowPacked,
|
||||
);
|
||||
}
|
||||
}
|
||||
let source_info = self.source_info;
|
||||
if let [] = proj_base {
|
||||
let decl = &self.body.local_decls[place.local];
|
||||
if decl.internal {
|
||||
|
@ -301,7 +308,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
self.source_info = old_source_info;
|
||||
self.source_info = source_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -314,9 +321,15 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
kind: UnsafetyViolationKind,
|
||||
) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root = self.body.source_scopes[self.source_info.scope]
|
||||
.local_data
|
||||
.as_ref()
|
||||
.assert_crate_local()
|
||||
.lint_root;
|
||||
self.register_violations(
|
||||
&[UnsafetyViolation {
|
||||
source_info,
|
||||
lint_root,
|
||||
description: Symbol::intern(description),
|
||||
details: Symbol::intern(details),
|
||||
kind,
|
||||
|
@ -343,7 +356,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
match violation.kind {
|
||||
UnsafetyViolationKind::GeneralAndConstFn
|
||||
| UnsafetyViolationKind::General => {}
|
||||
UnsafetyViolationKind::BorrowPacked(_) => {
|
||||
UnsafetyViolationKind::BorrowPacked => {
|
||||
if self.min_const_fn {
|
||||
// const fns don't need to be backwards compatible and can
|
||||
// emit these violations as a hard error instead of a backwards
|
||||
|
@ -351,6 +364,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
violation.kind = UnsafetyViolationKind::General;
|
||||
}
|
||||
}
|
||||
UnsafetyViolationKind::UnsafeFn
|
||||
| UnsafetyViolationKind::UnsafeFnBorrowPacked => {
|
||||
bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
|
||||
}
|
||||
}
|
||||
if !self.violations.contains(&violation) {
|
||||
self.violations.push(violation)
|
||||
|
@ -358,7 +375,23 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
false
|
||||
}
|
||||
// `unsafe` function bodies allow unsafe without additional unsafe blocks
|
||||
// With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
|
||||
Safety::FnUnsafe if self.tcx.features().unsafe_block_in_unsafe_fn => {
|
||||
for violation in violations {
|
||||
let mut violation = *violation;
|
||||
|
||||
if violation.kind == UnsafetyViolationKind::BorrowPacked {
|
||||
violation.kind = UnsafetyViolationKind::UnsafeFnBorrowPacked;
|
||||
} else {
|
||||
violation.kind = UnsafetyViolationKind::UnsafeFn;
|
||||
}
|
||||
if !self.violations.contains(&violation) {
|
||||
self.violations.push(violation)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
// `unsafe` function bodies allow unsafe without additional unsafe blocks (before RFC 2585)
|
||||
Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
|
||||
Safety::ExplicitUnsafe(hir_id) => {
|
||||
// mark unsafe block as used if there are any unsafe operations inside
|
||||
|
@ -373,7 +406,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
UnsafetyViolationKind::GeneralAndConstFn => {}
|
||||
// these things are forbidden in const fns
|
||||
UnsafetyViolationKind::General
|
||||
| UnsafetyViolationKind::BorrowPacked(_) => {
|
||||
| UnsafetyViolationKind::BorrowPacked => {
|
||||
let mut violation = *violation;
|
||||
// const fns don't need to be backwards compatible and can
|
||||
// emit these violations as a hard error instead of a backwards
|
||||
|
@ -383,6 +416,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
self.violations.push(violation)
|
||||
}
|
||||
}
|
||||
UnsafetyViolationKind::UnsafeFn
|
||||
| UnsafetyViolationKind::UnsafeFnBorrowPacked => bug!(
|
||||
"`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -575,9 +612,12 @@ fn is_enclosed(
|
|||
kind: hir::ItemKind::Fn(ref sig, _, _), ..
|
||||
})) = tcx.hir().find(parent_id)
|
||||
{
|
||||
match sig.header.unsafety {
|
||||
hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)),
|
||||
hir::Unsafety::Normal => None,
|
||||
if sig.header.unsafety == hir::Unsafety::Unsafe
|
||||
&& !tcx.features().unsafe_block_in_unsafe_fn
|
||||
{
|
||||
Some(("fn".to_string(), parent_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
is_enclosed(tcx, used_unsafe, parent_id)
|
||||
|
@ -630,33 +670,40 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
let UnsafetyCheckResult { violations, unsafe_blocks } =
|
||||
tcx.unsafety_check_result(def_id.expect_local());
|
||||
|
||||
for &UnsafetyViolation { source_info, description, details, kind } in violations.iter() {
|
||||
for &UnsafetyViolation { source_info, lint_root, description, details, kind } in
|
||||
violations.iter()
|
||||
{
|
||||
// Report an error.
|
||||
let unsafe_fn_msg =
|
||||
if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
|
||||
|
||||
match kind {
|
||||
UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {
|
||||
// once
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
source_info.span,
|
||||
E0133,
|
||||
"{} is unsafe and requires unsafe function or block",
|
||||
description
|
||||
"{} is unsafe and requires unsafe{} block",
|
||||
description,
|
||||
unsafe_fn_msg,
|
||||
)
|
||||
.span_label(source_info.span, &*description.as_str())
|
||||
.note(&details.as_str())
|
||||
.emit();
|
||||
}
|
||||
UnsafetyViolationKind::BorrowPacked(lint_hir_id) => {
|
||||
UnsafetyViolationKind::BorrowPacked => {
|
||||
if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) {
|
||||
tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id);
|
||||
} else {
|
||||
tcx.struct_span_lint_hir(
|
||||
SAFE_PACKED_BORROWS,
|
||||
lint_hir_id,
|
||||
lint_root,
|
||||
source_info.span,
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"{} is unsafe and requires unsafe function or block (error E0133)",
|
||||
description
|
||||
"{} is unsafe and requires unsafe{} block (error E0133)",
|
||||
description, unsafe_fn_msg,
|
||||
))
|
||||
.note(&details.as_str())
|
||||
.emit()
|
||||
|
@ -664,6 +711,49 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
)
|
||||
}
|
||||
}
|
||||
UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
lint_root,
|
||||
source_info.span,
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"{} is unsafe and requires unsafe block (error E0133)",
|
||||
description,
|
||||
))
|
||||
.span_label(source_info.span, &*description.as_str())
|
||||
.note(&details.as_str())
|
||||
.emit();
|
||||
},
|
||||
),
|
||||
UnsafetyViolationKind::UnsafeFnBorrowPacked => {
|
||||
// When `unsafe_op_in_unsafe_fn` is disallowed, the behavior of safe and unsafe functions
|
||||
// should be the same in terms of warnings and errors. Therefore, with `#[warn(safe_packed_borrows)]`,
|
||||
// a safe packed borrow should emit a warning *but not an error* in an unsafe function,
|
||||
// just like in a safe function, even if `unsafe_op_in_unsafe_fn` is `deny`.
|
||||
//
|
||||
// Also, `#[warn(unsafe_op_in_unsafe_fn)]` can't cause any new errors. Therefore, with
|
||||
// `#[deny(safe_packed_borrows)]` and `#[warn(unsafe_op_in_unsafe_fn)]`, a packed borrow
|
||||
// should only issue a warning for the sake of backwards compatibility.
|
||||
//
|
||||
// The solution those 2 expectations is to always take the minimum of both lints.
|
||||
// This prevent any new errors (unless both lints are explicitely set to `deny`).
|
||||
let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0
|
||||
<= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0
|
||||
{
|
||||
SAFE_PACKED_BORROWS
|
||||
} else {
|
||||
UNSAFE_OP_IN_UNSAFE_FN
|
||||
};
|
||||
tcx.struct_span_lint_hir(&lint, lint_root, source_info.span, |lint| {
|
||||
lint.build(&format!(
|
||||
"{} is unsafe and requires unsafe block (error E0133)",
|
||||
description,
|
||||
))
|
||||
.span_label(source_info.span, &*description.as_str())
|
||||
.note(&details.as_str())
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -683,3 +773,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
report_unused_unsafe(tcx, &unsafe_used, block_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool {
|
||||
tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
|
|||
use crate::hair::*;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::Span;
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
@ -217,6 +219,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
assert_eq!(self.push_unsafe_count, 0);
|
||||
match self.unpushed_unsafe {
|
||||
Safety::Safe => {}
|
||||
// no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585)
|
||||
Safety::FnUnsafe
|
||||
if self.hir.tcx().lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0
|
||||
!= Level::Allow => {}
|
||||
_ => return,
|
||||
}
|
||||
self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id);
|
||||
|
@ -231,7 +237,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
.push_unsafe_count
|
||||
.checked_sub(1)
|
||||
.unwrap_or_else(|| span_bug!(span, "unsafe count underflow"));
|
||||
if self.push_unsafe_count == 0 { Some(self.unpushed_unsafe) } else { None }
|
||||
if self.push_unsafe_count == 0 {
|
||||
Some(self.unpushed_unsafe)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -526,6 +526,12 @@ declare_lint! {
|
|||
"using only a subset of a register for inline asm inputs",
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub UNSAFE_OP_IN_UNSAFE_FN,
|
||||
Allow,
|
||||
"unsafe operations in unsafe functions without an explicit unsafe block are deprecated",
|
||||
}
|
||||
|
||||
declare_lint_pass! {
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// that are used by other parts of the compiler.
|
||||
|
@ -597,6 +603,7 @@ declare_lint_pass! {
|
|||
SOFT_UNSTABLE,
|
||||
INLINE_NO_SANITIZE,
|
||||
ASM_SUB_REGISTER,
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ symbols! {
|
|||
Arc,
|
||||
Arguments,
|
||||
ArgumentV1,
|
||||
arith_offset,
|
||||
arm_target_feature,
|
||||
asm,
|
||||
assert,
|
||||
|
@ -516,6 +517,7 @@ symbols! {
|
|||
not,
|
||||
note,
|
||||
object_safe_for_dispatch,
|
||||
offset,
|
||||
Ok,
|
||||
omit_gdb_pretty_printer_section,
|
||||
on,
|
||||
|
@ -806,6 +808,7 @@ symbols! {
|
|||
unmarked_api,
|
||||
unreachable_code,
|
||||
unrestricted_attribute_tokens,
|
||||
unsafe_block_in_unsafe_fn,
|
||||
unsafe_no_drop_flag,
|
||||
unsized_locals,
|
||||
unsized_tuple_coercion,
|
||||
|
|
|
@ -60,6 +60,7 @@ macro_rules! def_regs {
|
|||
#error = [$($bad_reg:literal),+] => $error:literal,
|
||||
)*
|
||||
}) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum $arch_reg {
|
||||
|
@ -102,19 +103,20 @@ macro_rules! def_regs {
|
|||
pub(super) fn fill_reg_map(
|
||||
_arch: super::InlineAsmArch,
|
||||
mut _has_feature: impl FnMut(&str) -> bool,
|
||||
map: &mut rustc_data_structures::fx::FxHashMap<
|
||||
_map: &mut rustc_data_structures::fx::FxHashMap<
|
||||
super::InlineAsmRegClass,
|
||||
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
|
||||
>,
|
||||
) {
|
||||
#[allow(unused_imports)]
|
||||
use super::{InlineAsmReg, InlineAsmRegClass};
|
||||
$(
|
||||
if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true {
|
||||
if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
|
||||
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
|
||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||
}
|
||||
$(
|
||||
if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
|
||||
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
|
||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||
}
|
||||
)*
|
||||
|
@ -146,11 +148,13 @@ macro_rules! types {
|
|||
|
||||
mod aarch64;
|
||||
mod arm;
|
||||
mod nvptx;
|
||||
mod riscv;
|
||||
mod x86;
|
||||
|
||||
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
|
||||
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
|
||||
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
|
||||
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
|
||||
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
|
||||
|
||||
|
@ -162,6 +166,7 @@ pub enum InlineAsmArch {
|
|||
AArch64,
|
||||
RiscV32,
|
||||
RiscV64,
|
||||
Nvptx64,
|
||||
}
|
||||
|
||||
impl FromStr for InlineAsmArch {
|
||||
|
@ -175,6 +180,7 @@ impl FromStr for InlineAsmArch {
|
|||
"aarch64" => Ok(Self::AArch64),
|
||||
"riscv32" => Ok(Self::RiscV32),
|
||||
"riscv64" => Ok(Self::RiscV64),
|
||||
"nvptx64" => Ok(Self::Nvptx64),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
@ -196,6 +202,7 @@ pub enum InlineAsmReg {
|
|||
Arm(ArmInlineAsmReg),
|
||||
AArch64(AArch64InlineAsmReg),
|
||||
RiscV(RiscVInlineAsmReg),
|
||||
Nvptx(NvptxInlineAsmReg),
|
||||
}
|
||||
|
||||
impl InlineAsmReg {
|
||||
|
@ -236,6 +243,9 @@ impl InlineAsmReg {
|
|||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?)
|
||||
}
|
||||
InlineAsmArch::Nvptx64 => {
|
||||
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -281,6 +291,7 @@ pub enum InlineAsmRegClass {
|
|||
Arm(ArmInlineAsmRegClass),
|
||||
AArch64(AArch64InlineAsmRegClass),
|
||||
RiscV(RiscVInlineAsmRegClass),
|
||||
Nvptx(NvptxInlineAsmRegClass),
|
||||
}
|
||||
|
||||
impl InlineAsmRegClass {
|
||||
|
@ -290,6 +301,7 @@ impl InlineAsmRegClass {
|
|||
Self::Arm(r) => r.name(),
|
||||
Self::AArch64(r) => r.name(),
|
||||
Self::RiscV(r) => r.name(),
|
||||
Self::Nvptx(r) => r.name(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,6 +314,7 @@ impl InlineAsmRegClass {
|
|||
Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
|
||||
Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
|
||||
Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
|
||||
Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,6 +334,7 @@ impl InlineAsmRegClass {
|
|||
Self::Arm(r) => r.suggest_modifier(arch, ty),
|
||||
Self::AArch64(r) => r.suggest_modifier(arch, ty),
|
||||
Self::RiscV(r) => r.suggest_modifier(arch, ty),
|
||||
Self::Nvptx(r) => r.suggest_modifier(arch, ty),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,6 +350,7 @@ impl InlineAsmRegClass {
|
|||
Self::Arm(r) => r.default_modifier(arch),
|
||||
Self::AArch64(r) => r.default_modifier(arch),
|
||||
Self::RiscV(r) => r.default_modifier(arch),
|
||||
Self::Nvptx(r) => r.default_modifier(arch),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,6 +365,7 @@ impl InlineAsmRegClass {
|
|||
Self::Arm(r) => r.supported_types(arch),
|
||||
Self::AArch64(r) => r.supported_types(arch),
|
||||
Self::RiscV(r) => r.supported_types(arch),
|
||||
Self::Nvptx(r) => r.supported_types(arch),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,6 +383,7 @@ impl InlineAsmRegClass {
|
|||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -379,6 +396,7 @@ impl InlineAsmRegClass {
|
|||
Self::Arm(r) => r.valid_modifiers(arch),
|
||||
Self::AArch64(r) => r.valid_modifiers(arch),
|
||||
Self::RiscV(r) => r.valid_modifiers(arch),
|
||||
Self::Nvptx(r) => r.valid_modifiers(arch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -518,5 +536,10 @@ pub fn allocatable_registers(
|
|||
riscv::fill_reg_map(arch, has_feature, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::Nvptx64 => {
|
||||
let mut map = nvptx::regclass_map();
|
||||
nvptx::fill_reg_map(arch, has_feature, &mut map);
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
def_reg_class! {
|
||||
Nvptx NvptxInlineAsmRegClass {
|
||||
reg16,
|
||||
reg32,
|
||||
reg64,
|
||||
}
|
||||
}
|
||||
|
||||
impl NvptxInlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
|
||||
&[]
|
||||
}
|
||||
|
||||
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
_ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg16 => types! { _: I8, I16; },
|
||||
Self::reg32 => types! { _: I8, I16, I32, F32; },
|
||||
Self::reg64 => types! { _: I8, I16, I32, F32, I64, F64; },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
// Registers in PTX are declared in the assembly.
|
||||
// There are no predefined registers that one can use.
|
||||
Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass {}
|
||||
}
|
|
@ -856,6 +856,8 @@ pub struct TargetOptions {
|
|||
/// the functions in the executable are not randomized and can be used
|
||||
/// during an exploit of a vulnerability in any code.
|
||||
pub position_independent_executables: bool,
|
||||
/// Executables that are both statically linked and position-independent are supported.
|
||||
pub static_position_independent_executables: bool,
|
||||
/// Determines if the target always requires using the PLT for indirect
|
||||
/// library calls or not. This controls the default value of the `-Z plt` flag.
|
||||
pub needs_plt: bool,
|
||||
|
@ -1029,6 +1031,7 @@ impl Default for TargetOptions {
|
|||
has_rpath: false,
|
||||
no_default_libraries: true,
|
||||
position_independent_executables: false,
|
||||
static_position_independent_executables: false,
|
||||
needs_plt: false,
|
||||
relro_level: RelroLevel::None,
|
||||
pre_link_objects: Default::default(),
|
||||
|
@ -1433,6 +1436,7 @@ impl Target {
|
|||
key!(has_rpath, bool);
|
||||
key!(no_default_libraries, bool);
|
||||
key!(position_independent_executables, bool);
|
||||
key!(static_position_independent_executables, bool);
|
||||
key!(needs_plt, bool);
|
||||
key!(relro_level, RelroLevel)?;
|
||||
key!(archive_format);
|
||||
|
@ -1664,6 +1668,7 @@ impl ToJson for Target {
|
|||
target_option_val!(has_rpath);
|
||||
target_option_val!(no_default_libraries);
|
||||
target_option_val!(position_independent_executables);
|
||||
target_option_val!(static_position_independent_executables);
|
||||
target_option_val!(needs_plt);
|
||||
target_option_val!(relro_level);
|
||||
target_option_val!(archive_format);
|
||||
|
|
|
@ -226,6 +226,11 @@ where
|
|||
{
|
||||
let warnings_lint_name = lint::builtin::WARNINGS.name;
|
||||
|
||||
// Whitelist feature-gated lints to avoid feature errors when trying to
|
||||
// allow all lints.
|
||||
// FIXME(#72694): handle feature-gated lints properly.
|
||||
let unsafe_op_in_unsafe_fn_name = rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN.name;
|
||||
|
||||
whitelisted_lints.push(warnings_lint_name.to_owned());
|
||||
whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
|
||||
|
||||
|
@ -236,7 +241,13 @@ where
|
|||
};
|
||||
|
||||
let lint_opts = lints()
|
||||
.filter_map(|lint| if lint.name == warnings_lint_name { None } else { filter_call(lint) })
|
||||
.filter_map(|lint| {
|
||||
if lint.name == warnings_lint_name || lint.name == unsafe_op_in_unsafe_fn_name {
|
||||
None
|
||||
} else {
|
||||
filter_call(lint)
|
||||
}
|
||||
})
|
||||
.chain(lint_opts.into_iter())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
)]
|
||||
|
||||
use crate::cmp::Ordering;
|
||||
use crate::fmt;
|
||||
use crate::fmt::{self, Write as FmtWrite};
|
||||
use crate::hash;
|
||||
use crate::io::Write;
|
||||
use crate::io::Write as IoWrite;
|
||||
use crate::sys::net::netc as c;
|
||||
use crate::sys_common::{AsInner, FromInner};
|
||||
|
||||
|
@ -1532,102 +1532,100 @@ impl Ipv6Addr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Write an Ipv6Addr, conforming to the canonical style described by
|
||||
/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for Ipv6Addr {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Note: The calls to write should never fail, hence the unwraps in the function
|
||||
// Long enough for the longest possible IPv6: 39
|
||||
const IPV6_BUF_LEN: usize = 39;
|
||||
let mut buf = [0u8; IPV6_BUF_LEN];
|
||||
let mut buf_slice = &mut buf[..];
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// If there are no alignment requirements, write out the IP address to
|
||||
// f. Otherwise, write it to a local buffer, then use f.pad.
|
||||
if f.precision().is_none() && f.width().is_none() {
|
||||
let segments = self.segments();
|
||||
|
||||
match self.segments() {
|
||||
// We need special cases for :: and ::1, otherwise they're formatted
|
||||
// as ::0.0.0.[01]
|
||||
[0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(),
|
||||
[0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(),
|
||||
// Ipv4 Compatible address
|
||||
[0, 0, 0, 0, 0, 0, g, h] => {
|
||||
write!(
|
||||
buf_slice,
|
||||
"::{}.{}.{}.{}",
|
||||
(g >> 8) as u8,
|
||||
g as u8,
|
||||
(h >> 8) as u8,
|
||||
h as u8
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
// Ipv4-Mapped address
|
||||
[0, 0, 0, 0, 0, 0xffff, g, h] => {
|
||||
write!(
|
||||
buf_slice,
|
||||
"::ffff:{}.{}.{}.{}",
|
||||
(g >> 8) as u8,
|
||||
g as u8,
|
||||
(h >> 8) as u8,
|
||||
h as u8
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
_ => {
|
||||
fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
|
||||
let mut longest_span_len = 0;
|
||||
let mut longest_span_at = 0;
|
||||
let mut cur_span_len = 0;
|
||||
let mut cur_span_at = 0;
|
||||
// Special case for :: and ::1; otherwise they get written with the
|
||||
// IPv4 formatter
|
||||
if self.is_unspecified() {
|
||||
f.write_str("::")
|
||||
} else if self.is_loopback() {
|
||||
f.write_str("::1")
|
||||
} else if let Some(ipv4) = self.to_ipv4() {
|
||||
match segments[5] {
|
||||
// IPv4 Compatible address
|
||||
0 => write!(f, "::{}", ipv4),
|
||||
// IPv4 Mapped address
|
||||
0xffff => write!(f, "::ffff:{}", ipv4),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
#[derive(Copy, Clone, Default)]
|
||||
struct Span {
|
||||
start: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
for i in 0..8 {
|
||||
if segments[i] == 0 {
|
||||
if cur_span_len == 0 {
|
||||
cur_span_at = i;
|
||||
// Find the inner 0 span
|
||||
let zeroes = {
|
||||
let mut longest = Span::default();
|
||||
let mut current = Span::default();
|
||||
|
||||
for (i, &segment) in segments.iter().enumerate() {
|
||||
if segment == 0 {
|
||||
if current.len == 0 {
|
||||
current.start = i;
|
||||
}
|
||||
|
||||
cur_span_len += 1;
|
||||
current.len += 1;
|
||||
|
||||
if cur_span_len > longest_span_len {
|
||||
longest_span_len = cur_span_len;
|
||||
longest_span_at = cur_span_at;
|
||||
if current.len > longest.len {
|
||||
longest = current;
|
||||
}
|
||||
} else {
|
||||
cur_span_len = 0;
|
||||
cur_span_at = 0;
|
||||
current = Span::default();
|
||||
}
|
||||
}
|
||||
|
||||
(longest_span_at, longest_span_len)
|
||||
longest
|
||||
};
|
||||
|
||||
/// Write a colon-separated part of the address
|
||||
#[inline]
|
||||
fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
|
||||
if let Some(first) = chunk.first() {
|
||||
fmt::LowerHex::fmt(first, f)?;
|
||||
for segment in &chunk[1..] {
|
||||
f.write_char(':')?;
|
||||
fmt::LowerHex::fmt(segment, f)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
|
||||
|
||||
if zeros_len > 1 {
|
||||
fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) {
|
||||
if !segments.is_empty() {
|
||||
write!(*buf, "{:x}", segments[0]).unwrap();
|
||||
for &seg in &segments[1..] {
|
||||
write!(*buf, ":{:x}", seg).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice);
|
||||
write!(buf_slice, "::").unwrap();
|
||||
fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice);
|
||||
if zeroes.len > 1 {
|
||||
fmt_subslice(f, &segments[..zeroes.start])?;
|
||||
f.write_str("::")?;
|
||||
fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
|
||||
} else {
|
||||
let &[a, b, c, d, e, f, g, h] = &self.segments();
|
||||
write!(
|
||||
buf_slice,
|
||||
"{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
|
||||
a, b, c, d, e, f, g, h
|
||||
)
|
||||
.unwrap();
|
||||
fmt_subslice(f, &segments)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Slow path: write the address to a local buffer, the use f.pad.
|
||||
// Defined recursively by using the fast path to write to the
|
||||
// buffer.
|
||||
|
||||
// This is the largest possible size of an IPv6 address
|
||||
const IPV6_BUF_LEN: usize = (4 * 8) + 7;
|
||||
let mut buf = [0u8; IPV6_BUF_LEN];
|
||||
let mut buf_slice = &mut buf[..];
|
||||
|
||||
// Note: This call to write should never fail, so unwrap is okay.
|
||||
write!(buf_slice, "{}", self).unwrap();
|
||||
let len = IPV6_BUF_LEN - buf_slice.len();
|
||||
|
||||
// This is safe because we know exactly what can be in this buffer
|
||||
let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
|
||||
f.pad(buf)
|
||||
}
|
||||
let len = IPV6_BUF_LEN - buf_slice.len();
|
||||
// This is safe because we know exactly what can be in this buffer
|
||||
let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
|
||||
fmt.pad(buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
// no-system-llvm
|
||||
// assembly-output: emit-asm
|
||||
// compile-flags: --target nvptx64-nvidia-cuda
|
||||
// compile-flags: --crate-type cdylib
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs)]
|
||||
#![no_core]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
type ptr = *mut u8;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
// NVPTX does not support static variables
|
||||
#[no_mangle]
|
||||
fn extern_func() {}
|
||||
|
||||
// CHECK-LABEL: .visible .func sym_fn()
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: call extern_func;
|
||||
// CHECK: // end inline asm
|
||||
#[no_mangle]
|
||||
pub unsafe fn sym_fn() {
|
||||
asm!("call {};", sym extern_func);
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $ty:ident $class:ident $mov:literal) => {
|
||||
#[no_mangle]
|
||||
pub unsafe fn $func(x: $ty) -> $ty {
|
||||
let y;
|
||||
asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x);
|
||||
y
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i8
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg16_i8 i8 reg16 "mov.i16");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i16
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg16_i16 i16 reg16 "mov.i16");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i8
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg32_i8 i8 reg32 "mov.i32");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i16
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg32_i16 i16 reg32 "mov.i32");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i32
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg32_i32 i32 reg32 "mov.i32");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_f32
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg32_f32 f32 reg32 "mov.i32");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i8
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg64_i8 i8 reg64 "mov.i64");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i16
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg64_i16 i16 reg64 "mov.i64");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i32
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg64_i32 i32 reg64 "mov.i64");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_f32
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg64_f32 f32 reg64 "mov.i64");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_i64
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg64_i64 i64 reg64 "mov.i64");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_f64
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg64_f64 f64 reg64 "mov.i64");
|
||||
|
||||
// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_ptr
|
||||
// CHECK: // begin inline asm
|
||||
// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
|
||||
// CHECK: // end inline asm
|
||||
check!(reg64_ptr ptr reg64 "mov.i64");
|
|
@ -14,16 +14,16 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | bar(foo, x)
|
||||
| ^
|
||||
= note: expected `Type<'_>`
|
||||
found `Type<'a>`
|
||||
= note: expected `Type<'_>`
|
||||
found `Type<'a>`
|
||||
= note: but, the lifetime must be valid for the static lifetime...
|
||||
note: ...so that the expression is assignable
|
||||
--> $DIR/project-fn-ret-invariant.rs:48:4
|
||||
|
|
||||
LL | bar(foo, x)
|
||||
| ^^^^^^^^^^^
|
||||
= note: expected `Type<'static>`
|
||||
found `Type<'_>`
|
||||
= note: expected `Type<'static>`
|
||||
found `Type<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@ pub fn yes_array_into_vec<T>() -> Vec<T> {
|
|||
[].into()
|
||||
}
|
||||
|
||||
pub fn yes_array_into_box<T>() -> Box<[T]> {
|
||||
[].into()
|
||||
}
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub fn yes_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 32]>
|
||||
|
|
|
@ -12,6 +12,8 @@ pub fn no_box() {
|
|||
let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
|
||||
//~^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::From<std::boxed::Box<[i32]>>` is not satisfied
|
||||
//~^^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom<std::boxed::Box<[i32]>>` is not satisfied
|
||||
let boxed_slice = <Box<[i32]>>::from([0; 33]);
|
||||
//~^ 15:42: 15:49: arrays only have std trait implementations for lengths 0..=32 [E0277]
|
||||
}
|
||||
|
||||
pub fn no_rc() {
|
||||
|
|
|
@ -18,10 +18,23 @@ LL | let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
|
|||
<std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<&str>>
|
||||
<std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<std::borrow::Cow<'a, str>>>
|
||||
<std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<std::string::String>>
|
||||
and 21 others
|
||||
and 22 others
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<std::boxed::Box<[i32; 33]>>` for `std::boxed::Box<[i32]>`
|
||||
= note: required because of the requirements on the impl of `std::convert::TryFrom<std::boxed::Box<[i32]>>` for `std::boxed::Box<[i32; 33]>`
|
||||
|
||||
error[E0277]: arrays only have std trait implementations for lengths 0..=32
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:15:42
|
||||
|
|
||||
LL | let boxed_slice = <Box<[i32]>>::from([0; 33]);
|
||||
| ^^^^^^^
|
||||
| |
|
||||
| expected an implementor of trait `std::convert::From<[{integer}; 33]>`
|
||||
| help: consider borrowing here: `&[0; 33]`
|
||||
|
|
||||
= note: the trait bound `[i32; 33]: std::convert::From<[{integer}; 33]>` is not satisfied
|
||||
= note: required because of the requirements on the impl of `std::convert::From<[i32; 33]>` for `std::boxed::Box<[i32]>`
|
||||
= note: required by `std::convert::From::from`
|
||||
|
||||
error[E0277]: the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom<std::boxed::Box<[i32]>>` is not satisfied
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:12:23
|
||||
|
|
||||
|
@ -32,7 +45,7 @@ LL | let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
|
|||
<std::boxed::Box<[T; N]> as std::convert::TryFrom<std::boxed::Box<[T]>>>
|
||||
|
||||
error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From<std::rc::Rc<[i32]>>` is not satisfied
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:19:23
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:21:23
|
||||
|
|
||||
LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::rc::Rc<[i32]>>` is not implemented for `std::rc::Rc<[i32; 33]>`
|
||||
|
@ -47,7 +60,7 @@ LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
|
|||
= note: required because of the requirements on the impl of `std::convert::TryFrom<std::rc::Rc<[i32]>>` for `std::rc::Rc<[i32; 33]>`
|
||||
|
||||
error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::TryFrom<std::rc::Rc<[i32]>>` is not satisfied
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:19:23
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:21:23
|
||||
|
|
||||
LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::rc::Rc<[i32]>>` is not implemented for `std::rc::Rc<[i32; 33]>`
|
||||
|
@ -56,7 +69,7 @@ LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
|
|||
<std::rc::Rc<[T; N]> as std::convert::TryFrom<std::rc::Rc<[T]>>>
|
||||
|
||||
error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From<std::sync::Arc<[i32]>>` is not satisfied
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:26:23
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:28:23
|
||||
|
|
||||
LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::sync::Arc<[i32]>>` is not implemented for `std::sync::Arc<[i32; 33]>`
|
||||
|
@ -71,7 +84,7 @@ LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
|
|||
= note: required because of the requirements on the impl of `std::convert::TryFrom<std::sync::Arc<[i32]>>` for `std::sync::Arc<[i32; 33]>`
|
||||
|
||||
error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::TryFrom<std::sync::Arc<[i32]>>` is not satisfied
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:26:23
|
||||
--> $DIR/alloc-types-no-impls-length-33.rs:28:23
|
||||
|
|
||||
LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::sync::Arc<[i32]>>` is not implemented for `std::sync::Arc<[i32; 33]>`
|
||||
|
@ -79,6 +92,6 @@ LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
|
|||
= help: the following implementations were found:
|
||||
<std::sync::Arc<[T; N]> as std::convert::TryFrom<std::sync::Arc<[T]>>>
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![allow(const_err)]
|
||||
|
||||
// A test demonstrating that we prevent doing even trivial
|
||||
// pointer arithmetic or comparison during CTFE.
|
||||
// During CTFE, we prevent pointer comparison and pointer-to-int casts.
|
||||
|
||||
static CMP: () = {
|
||||
let x = &0 as *const _;
|
||||
|
@ -19,11 +18,4 @@ static INT_PTR_ARITH: () = unsafe {
|
|||
//~| NOTE pointer-to-integer cast
|
||||
};
|
||||
|
||||
static PTR_ARITH: () = unsafe {
|
||||
let x = &0 as *const _;
|
||||
let _v = core::intrinsics::offset(x, 0);
|
||||
//~^ ERROR could not evaluate static initializer
|
||||
//~| NOTE calling intrinsic `offset`
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,39 +1,28 @@
|
|||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/ptr_arith.rs:10:14
|
||||
--> $DIR/ptr_arith.rs:9:14
|
||||
|
|
||||
LL | let _v = x == x;
|
||||
| ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
|
||||
|
||||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/ptr_arith.rs:17:14
|
||||
--> $DIR/ptr_arith.rs:16:14
|
||||
|
|
||||
LL | let _v = x + 0;
|
||||
| ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
|
||||
|
||||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/ptr_arith.rs:24:14
|
||||
|
|
||||
LL | let _v = core::intrinsics::offset(x, 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants
|
||||
|
||||
warning: skipping const checks
|
||||
|
|
||||
help: skipping check for `const_compare_raw_pointers` feature
|
||||
--> $DIR/ptr_arith.rs:10:14
|
||||
--> $DIR/ptr_arith.rs:9:14
|
||||
|
|
||||
LL | let _v = x == x;
|
||||
| ^^^^^^
|
||||
help: skipping check that does not even have a feature gate
|
||||
--> $DIR/ptr_arith.rs:16:20
|
||||
--> $DIR/ptr_arith.rs:15:20
|
||||
|
|
||||
LL | let x: usize = std::mem::transmute(&0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check that does not even have a feature gate
|
||||
--> $DIR/ptr_arith.rs:24:14
|
||||
|
|
||||
LL | let _v = core::intrinsics::offset(x, 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
// run-pass
|
||||
#![feature(const_ptr_offset)]
|
||||
#![feature(const_ptr_offset_from)]
|
||||
#![feature(ptr_offset_from)]
|
||||
use std::ptr;
|
||||
|
||||
#[repr(C)]
|
||||
struct Struct {
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: u32,
|
||||
}
|
||||
static S: Struct = Struct { a: 0, b: 0, c: 0 };
|
||||
|
||||
// For these tests we use offset_from to check that two pointers are equal.
|
||||
// Rust doesn't currently support comparing pointers in const fn.
|
||||
|
||||
static OFFSET_NO_CHANGE: bool = unsafe {
|
||||
let p1 = &S.b as *const u32;
|
||||
let p2 = p1.offset(2).offset(-2);
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
static OFFSET_MIDDLE: bool = unsafe {
|
||||
let p1 = (&S.a as *const u32).offset(1);
|
||||
let p2 = (&S.c as *const u32).offset(-1);
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
// Pointing to the end of the allocation is OK
|
||||
static OFFSET_END: bool = unsafe {
|
||||
let p1 = (&S.a as *const u32).offset(3);
|
||||
let p2 = (&S.c as *const u32).offset(1);
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
// Casting though a differently sized type is OK
|
||||
static OFFSET_U8_PTR: bool = unsafe {
|
||||
let p1 = (&S.a as *const u32 as *const u8).offset(5);
|
||||
let p2 = (&S.c as *const u32 as *const u8).offset(-3);
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
// Any offset with a ZST does nothing
|
||||
const OFFSET_ZST: bool = unsafe {
|
||||
let pz = &() as *const ();
|
||||
// offset_from can't work with ZSTs, so cast to u8 ptr
|
||||
let p1 = pz.offset(5) as *const u8;
|
||||
let p2 = pz.offset(isize::MIN) as *const u8;
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
const OFFSET_ZERO: bool = unsafe {
|
||||
let p = [0u8; 0].as_ptr();
|
||||
p.offset(0).offset_from(p) == 0
|
||||
};
|
||||
const OFFSET_ONE: bool = unsafe {
|
||||
let p = &42u32 as *const u32;
|
||||
p.offset(1).offset_from(p) == 1
|
||||
};
|
||||
const OFFSET_DANGLING: bool = unsafe {
|
||||
let p = ptr::NonNull::<u8>::dangling().as_ptr();
|
||||
p.offset(0).offset_from(p) == 0
|
||||
};
|
||||
const OFFSET_UNALIGNED: bool = unsafe {
|
||||
let arr = [0u8; 32];
|
||||
let p1 = arr.as_ptr();
|
||||
let p2 = (p1.offset(2) as *const u32).offset(1);
|
||||
(p2 as *const u8).offset_from(p1) == 6
|
||||
};
|
||||
|
||||
const WRAP_OFFSET_NO_CHANGE: bool = unsafe {
|
||||
let p1 = &42u32 as *const u32;
|
||||
let p2 = p1.wrapping_offset(1000).wrapping_offset(-1000);
|
||||
let p3 = p1.wrapping_offset(-1000).wrapping_offset(1000);
|
||||
(p1.offset_from(p2) == 0) & (p1.offset_from(p3) == 0)
|
||||
};
|
||||
const WRAP_ADDRESS_SPACE: bool = unsafe {
|
||||
let p1 = &42u8 as *const u8;
|
||||
let p2 = p1.wrapping_offset(isize::MIN).wrapping_offset(isize::MIN);
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
// Wrap on the count*size_of::<T>() calculation.
|
||||
const WRAP_SIZE_OF: bool = unsafe {
|
||||
// Make sure that if p1 moves backwards, we are still in range
|
||||
let arr = [0u32; 2];
|
||||
let p = &arr[1] as *const u32;
|
||||
// With wrapping arithmetic, isize::MAX * 4 == -4
|
||||
let wrapped = p.wrapping_offset(isize::MAX);
|
||||
let backward = p.wrapping_offset(-1);
|
||||
wrapped.offset_from(backward) == 0
|
||||
};
|
||||
const WRAP_INTEGER_POINTER: bool = unsafe {
|
||||
let p1 = (0x42 as *const u32).wrapping_offset(4);
|
||||
let p2 = 0x52 as *const u32;
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
const WRAP_NULL: bool = unsafe {
|
||||
let p1 = ptr::null::<u32>().wrapping_offset(1);
|
||||
let p2 = 0x4 as *const u32;
|
||||
p1.offset_from(p2) == 0
|
||||
};
|
||||
|
||||
fn main() {
|
||||
assert!(OFFSET_NO_CHANGE);
|
||||
assert!(OFFSET_MIDDLE);
|
||||
assert!(OFFSET_END);
|
||||
assert!(OFFSET_U8_PTR);
|
||||
assert!(OFFSET_ZST);
|
||||
assert!(OFFSET_ZERO);
|
||||
assert!(OFFSET_ONE);
|
||||
assert!(OFFSET_DANGLING);
|
||||
assert!(OFFSET_UNALIGNED);
|
||||
|
||||
assert!(WRAP_OFFSET_NO_CHANGE);
|
||||
assert!(WRAP_ADDRESS_SPACE);
|
||||
assert!(WRAP_SIZE_OF);
|
||||
assert!(WRAP_INTEGER_POINTER);
|
||||
assert!(WRAP_NULL);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// ignore-tidy-linelength
|
||||
#![feature(const_ptr_offset)]
|
||||
use std::ptr;
|
||||
|
||||
// normalize-stderr-test "alloc\d+" -> "allocN"
|
||||
|
||||
pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~NOTE
|
||||
pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~NOTE
|
||||
pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~NOTE
|
||||
|
||||
pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~NOTE
|
||||
pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~NOTE
|
||||
pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~NOTE
|
||||
pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~NOTE
|
||||
|
||||
pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~NOTE
|
||||
pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; //~NOTE
|
||||
|
||||
// Right now, a zero offset from null is UB
|
||||
pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) }; //~NOTE
|
||||
|
||||
// Make sure that we don't panic when computing abs(offset*size_of::<T>())
|
||||
pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; //~NOTE
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,169 @@
|
|||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| overflowing in-bounds pointer arithmetic
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `BEFORE_START` at $DIR/offset_ub.rs:7:46
|
||||
|
|
||||
::: $DIR/offset_ub.rs:7:1
|
||||
|
|
||||
LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) };
|
||||
| ------------------------------------------------------------------------------
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `AFTER_END` at $DIR/offset_ub.rs:8:43
|
||||
|
|
||||
::: $DIR/offset_ub.rs:8:1
|
||||
|
|
||||
LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) };
|
||||
| --------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45
|
||||
|
|
||||
::: $DIR/offset_ub.rs:9:1
|
||||
|
|
||||
LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) };
|
||||
| ------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| overflowing in-bounds pointer arithmetic
|
||||
| inside `std::ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `OVERFLOW` at $DIR/offset_ub.rs:11:43
|
||||
|
|
||||
::: $DIR/offset_ub.rs:11:1
|
||||
|
|
||||
LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) };
|
||||
| ----------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| overflowing in-bounds pointer arithmetic
|
||||
| inside `std::ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44
|
||||
|
|
||||
::: $DIR/offset_ub.rs:12:1
|
||||
|
|
||||
LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) };
|
||||
| -----------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| overflowing in-bounds pointer arithmetic
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56
|
||||
|
|
||||
::: $DIR/offset_ub.rs:13:1
|
||||
|
|
||||
LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) };
|
||||
| ---------------------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| overflowing in-bounds pointer arithmetic
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57
|
||||
|
|
||||
::: $DIR/offset_ub.rs:14:1
|
||||
|
|
||||
LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) };
|
||||
| --------------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50
|
||||
|
|
||||
::: $DIR/offset_ub.rs:16:1
|
||||
|
|
||||
LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) };
|
||||
| -------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count) as *mut T
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| unable to turn bytes into a pointer
|
||||
| inside `std::ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL
|
||||
| inside `DANGLING` at $DIR/offset_ub.rs:17:42
|
||||
|
|
||||
::: $DIR/offset_ub.rs:17:1
|
||||
|
|
||||
LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) };
|
||||
| ---------------------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| inbounds test failed: 0x0 is not a valid pointer
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50
|
||||
|
|
||||
::: $DIR/offset_ub.rs:20:1
|
||||
|
|
||||
LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) };
|
||||
| -------------------------------------------------------------------------------
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::offset(self, count)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| unable to turn bytes into a pointer
|
||||
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
| inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47
|
||||
|
|
||||
::: $DIR/offset_ub.rs:23:1
|
||||
|
|
||||
LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) };
|
||||
| ---------------------------------------------------------------------------------------------
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
|
@ -58,8 +58,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | let x: &'a _ = &y;
|
||||
| ^^
|
||||
= note: expected `&'a &()`
|
||||
found `&'a &'b ()`
|
||||
= note: expected `&'a &()`
|
||||
found `&'a &'b ()`
|
||||
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6...
|
||||
--> $DIR/E0490.rs:1:6
|
||||
|
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
//~^ ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,30 @@
|
|||
error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
--> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
|
||||
= help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
--> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
|
||||
= help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
|
||||
--> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
|
||||
= help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
|
@ -14,16 +14,16 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | static_val(x);
|
||||
| ^
|
||||
= note: expected `std::boxed::Box<dyn std::fmt::Debug>`
|
||||
found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
|
||||
= note: expected `std::boxed::Box<dyn std::fmt::Debug>`
|
||||
found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
|
||||
= note: but, the lifetime must be valid for the static lifetime...
|
||||
note: ...so that the types are compatible
|
||||
--> $DIR/dyn-trait.rs:20:5
|
||||
|
|
||||
LL | static_val(x);
|
||||
| ^^^^^^^^^^
|
||||
= note: expected `StaticTrait`
|
||||
found `StaticTrait`
|
||||
= note: expected `StaticTrait`
|
||||
found `StaticTrait`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,15 +2,17 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/mismatched_trait_impl-2.rs:8:5
|
||||
|
|
||||
LL | fn deref(&self) -> &dyn Trait {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
|
||||
|
|
||||
::: $SRC_DIR/libcore/ops/deref.rs:LL:COL
|
||||
|
|
||||
LL | fn deref(&self) -> &Self::Target;
|
||||
| --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static)
|
||||
| --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
|
||||
|
|
||||
= note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
|
||||
found `fn(&Struct) -> &dyn Trait`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/mismatched_trait_impl.rs:9:5
|
||||
|
|
||||
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
|
||||
| ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
|
||||
| ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
...
|
||||
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
|
||||
|
|
||||
= note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
found `fn(&i32, &u32, &u32) -> &u32`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/mismatched_trait_impl.rs:9:5
|
||||
|
|
||||
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
|
||||
| ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
|
||||
| ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
...
|
||||
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
|
||||
|
|
||||
= note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
found `fn(&i32, &u32, &u32) -> &u32`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error[E0623]: lifetime mismatch
|
||||
--> $DIR/mismatched_trait_impl.rs:10:9
|
||||
|
|
|
@ -26,8 +26,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | self.a();
|
||||
| ^
|
||||
= note: expected `&'a Self`
|
||||
found `&Self`
|
||||
= note: expected `&'a Self`
|
||||
found `&Self`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | self.foo();
|
||||
| ^^^
|
||||
= note: expected `&'a Self`
|
||||
found `&Self`
|
||||
= note: expected `&'a Self`
|
||||
found `&Self`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -87,8 +87,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `Publisher<'_>`
|
||||
found `Publisher<'_>`
|
||||
= note: expected `Publisher<'_>`
|
||||
found `Publisher<'_>`
|
||||
|
||||
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
|
||||
--> $DIR/issue-20831-debruijn.rs:28:33
|
||||
|
@ -117,8 +117,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `Publisher<'_>`
|
||||
found `Publisher<'_>`
|
||||
= note: expected `Publisher<'_>`
|
||||
found `Publisher<'_>`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | match (&t,) {
|
||||
| ^^^^^
|
||||
= note: expected `(&&(T,),)`
|
||||
found `(&&'a (T,),)`
|
||||
= note: expected `(&&(T,),)`
|
||||
found `(&&'a (T,),)`
|
||||
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27...
|
||||
--> $DIR/issue-52213.rs:1:27
|
||||
|
|
||||
|
|
|
@ -20,8 +20,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Box::new(self.out_edges(u).map(|e| e.target()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
|
||||
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
|
||||
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
|
||||
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
|
||||
|
||||
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||
--> $DIR/issue-55796.rs:21:9
|
||||
|
@ -45,8 +45,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Box::new(self.in_edges(u).map(|e| e.target()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
|
||||
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
|
||||
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
|
||||
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
|
||||
|
|
||||
LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
|
||||
| ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32
|
||||
| ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
|
||||
...
|
||||
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
|
||||
|
|
||||
= note: expected `fn(&i32, &'a i32) -> &'a i32`
|
||||
found `fn(&i32, &i32) -> &i32`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Foo { bar }
|
||||
| ^^^^^^^^^^^
|
||||
= note: expected `Foo<'_>`
|
||||
found `Foo<'_>`
|
||||
= note: expected `Foo<'_>`
|
||||
found `Foo<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `Visitor<'d>`
|
||||
found `Visitor<'_>`
|
||||
= note: expected `Visitor<'d>`
|
||||
found `Visitor<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | C { f: b }
|
||||
| ^
|
||||
= note: expected `std::boxed::Box<std::boxed::Box<&isize>>`
|
||||
found `std::boxed::Box<std::boxed::Box<&isize>>`
|
||||
= note: expected `std::boxed::Box<std::boxed::Box<&isize>>`
|
||||
found `std::boxed::Box<std::boxed::Box<&isize>>`
|
||||
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
|
||||
--> $DIR/type-alias-free-regions.rs:15:6
|
||||
|
|
||||
|
@ -28,8 +28,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | C { f: b }
|
||||
| ^^^^^^^^^^
|
||||
= note: expected `C<'a>`
|
||||
found `C<'_>`
|
||||
= note: expected `C<'a>`
|
||||
found `C<'_>`
|
||||
|
||||
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||
--> $DIR/type-alias-free-regions.rs:27:16
|
||||
|
@ -49,8 +49,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | C { f: Box::new(b.0) }
|
||||
| ^^^
|
||||
= note: expected `std::boxed::Box<&isize>`
|
||||
found `std::boxed::Box<&isize>`
|
||||
= note: expected `std::boxed::Box<&isize>`
|
||||
found `std::boxed::Box<&isize>`
|
||||
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6...
|
||||
--> $DIR/type-alias-free-regions.rs:25:6
|
||||
|
|
||||
|
@ -61,8 +61,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | C { f: Box::new(b.0) }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `C<'a>`
|
||||
found `C<'_>`
|
||||
= note: expected `C<'a>`
|
||||
found `C<'_>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | <Foo<'a>>::C
|
||||
| ^^^^^^^^^^^^
|
||||
= note: expected `Foo<'_>`
|
||||
found `Foo<'a>`
|
||||
= note: expected `Foo<'_>`
|
||||
found `Foo<'a>`
|
||||
= note: but, the lifetime must be valid for the static lifetime...
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/constant-in-expr-inherent-1.rs:8:5
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | T::C
|
||||
| ^^^^
|
||||
= note: expected `Foo<'_>`
|
||||
found `Foo<'a>`
|
||||
= note: expected `Foo<'_>`
|
||||
found `Foo<'a>`
|
||||
= note: but, the lifetime must be valid for the static lifetime...
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/constant-in-expr-trait-item-3.rs:10:5
|
||||
|
|
|
@ -24,8 +24,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | ss
|
||||
| ^^
|
||||
= note: expected `&'b (dyn SomeTrait + 'b)`
|
||||
found `&dyn SomeTrait`
|
||||
= note: expected `&'b (dyn SomeTrait + 'b)`
|
||||
found `&dyn SomeTrait`
|
||||
|
||||
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||
--> $DIR/object-lifetime-default-elision.rs:71:5
|
||||
|
@ -53,8 +53,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | ss
|
||||
| ^^
|
||||
= note: expected `&'b (dyn SomeTrait + 'b)`
|
||||
found `&dyn SomeTrait`
|
||||
= note: expected `&'b (dyn SomeTrait + 'b)`
|
||||
found `&dyn SomeTrait`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Box::new(v)
|
||||
| ^
|
||||
= note: expected `&[u8]`
|
||||
found `&'a [u8]`
|
||||
= note: expected `&[u8]`
|
||||
found `&'a [u8]`
|
||||
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9...
|
||||
--> $DIR/region-object-lifetime-in-coercion.rs:25:9
|
||||
|
|
||||
|
@ -51,8 +51,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Box::new(v)
|
||||
| ^^^^^^^^^^^
|
||||
= note: expected `std::boxed::Box<(dyn Foo + 'b)>`
|
||||
found `std::boxed::Box<dyn Foo>`
|
||||
= note: expected `std::boxed::Box<(dyn Foo + 'b)>`
|
||||
found `std::boxed::Box<dyn Foo>`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | impl<'a> Foo<'static> for &'a i32 {
|
||||
| ^^^^^^^^^^^^
|
||||
= note: expected `Foo<'static>`
|
||||
found `Foo<'static>`
|
||||
= note: expected `Foo<'static>`
|
||||
found `Foo<'static>`
|
||||
= note: but, the lifetime must be valid for the static lifetime...
|
||||
note: ...so that the type `&i32` will meet its required lifetime bounds
|
||||
--> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
|
||||
|
@ -39,8 +39,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | impl<'a,'b> Foo<'b> for &'a i64 {
|
||||
| ^^^^^^^
|
||||
= note: expected `Foo<'b>`
|
||||
found `Foo<'_>`
|
||||
= note: expected `Foo<'b>`
|
||||
found `Foo<'_>`
|
||||
note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9...
|
||||
--> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9
|
||||
|
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | impl<'a> Foo for &'a i32 {
|
||||
| ^^^
|
||||
= note: expected `Foo`
|
||||
found `Foo`
|
||||
= note: expected `Foo`
|
||||
found `Foo`
|
||||
= note: but, the lifetime must be valid for the static lifetime...
|
||||
note: ...so that the type `&i32` will meet its required lifetime bounds
|
||||
--> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
|
||||
|
|
|
@ -20,8 +20,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | box B(&*v) as Box<dyn X>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `std::boxed::Box<(dyn X + 'static)>`
|
||||
found `std::boxed::Box<dyn X>`
|
||||
= note: expected `std::boxed::Box<(dyn X + 'static)>`
|
||||
found `std::boxed::Box<dyn X>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | box B(&*v) as Box<dyn X>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `std::boxed::Box<(dyn X + 'static)>`
|
||||
found `std::boxed::Box<dyn X>`
|
||||
= note: expected `std::boxed::Box<(dyn X + 'static)>`
|
||||
found `std::boxed::Box<dyn X>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | box v as Box<dyn SomeTrait + 'a>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>`
|
||||
found `std::boxed::Box<dyn SomeTrait>`
|
||||
= note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>`
|
||||
found `std::boxed::Box<dyn SomeTrait>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Ast::Add(x, y)
|
||||
| ^
|
||||
= note: expected `&Ast<'_>`
|
||||
found `&Ast<'a>`
|
||||
= note: expected `&Ast<'_>`
|
||||
found `&Ast<'a>`
|
||||
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19...
|
||||
--> $DIR/regions-creating-enums4.rs:6:19
|
||||
|
|
||||
|
@ -26,8 +26,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Ast::Add(x, y)
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: expected `Ast<'b>`
|
||||
found `Ast<'_>`
|
||||
= note: expected `Ast<'b>`
|
||||
found `Ast<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ LL | | if false { return ay; }
|
|||
LL | | return z;
|
||||
LL | | }));
|
||||
| |_____^
|
||||
= note: expected `&isize`
|
||||
found `&isize`
|
||||
= note: expected `&isize`
|
||||
found `&isize`
|
||||
|
||||
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
|
||||
--> $DIR/regions-nested-fns.rs:14:27
|
||||
|
|
|
@ -29,8 +29,8 @@ LL | | where <() as Project<'a, 'b>>::Item : Eq
|
|||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected `Project<'a, 'b>`
|
||||
found `Project<'_, '_>`
|
||||
= note: expected `Project<'a, 'b>`
|
||||
found `Project<'_, '_>`
|
||||
|
||||
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
|
||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:1
|
||||
|
@ -63,8 +63,8 @@ LL | | where <() as Project<'a, 'b>>::Item : Eq
|
|||
LL | | {
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: expected `Project<'a, 'b>`
|
||||
found `Project<'_, '_>`
|
||||
= note: expected `Project<'a, 'b>`
|
||||
found `Project<'_, '_>`
|
||||
|
||||
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
|
||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:4
|
||||
|
@ -87,8 +87,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | fn bar<'a, 'b>()
|
||||
| ^^^
|
||||
= note: expected `Project<'a, 'b>`
|
||||
found `Project<'_, '_>`
|
||||
= note: expected `Project<'a, 'b>`
|
||||
found `Project<'_, '_>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | with(|o| o)
|
||||
| ^
|
||||
= note: expected `&isize`
|
||||
found `&isize`
|
||||
= note: expected `&isize`
|
||||
found `&isize`
|
||||
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14...
|
||||
--> $DIR/regions-ret-borrowed-1.rs:9:14
|
||||
|
|
||||
|
|
|
@ -14,8 +14,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | with(|o| o)
|
||||
| ^
|
||||
= note: expected `&isize`
|
||||
found `&isize`
|
||||
= note: expected `&isize`
|
||||
found `&isize`
|
||||
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14...
|
||||
--> $DIR/regions-ret-borrowed.rs:12:14
|
||||
|
|
||||
|
|
|
@ -41,8 +41,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | x
|
||||
| ^
|
||||
= note: expected `&'b mut (dyn Dummy + 'b)`
|
||||
found `&mut (dyn Dummy + 'b)`
|
||||
= note: expected `&'b mut (dyn Dummy + 'b)`
|
||||
found `&mut (dyn Dummy + 'b)`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/regions-trait-object-subtyping.rs:22:5
|
||||
|
|
|
@ -118,8 +118,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `W<'l1, 'l2>`
|
||||
found `W<'_, '_>`
|
||||
= note: expected `W<'l1, 'l2>`
|
||||
found `W<'_, '_>`
|
||||
|
||||
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:61:14
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ValueRef<'a> {
|
||||
Null,
|
||||
Integer(i64),
|
||||
Real(f64),
|
||||
Text(&'a [u8]),
|
||||
Blob(&'a [u8]),
|
||||
}
|
||||
|
||||
impl<'a> ValueRef<'a> {
|
||||
pub fn as_str(&self) -> FromSqlResult<&'a str, &'a &'a str> {
|
||||
match *self {
|
||||
ValueRef::Text(t) => {
|
||||
std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType).map(|x| (x, &x))
|
||||
}
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum FromSqlError {
|
||||
InvalidType
|
||||
}
|
||||
|
||||
impl fmt::Display for FromSqlError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "InvalidType")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for FromSqlError {}
|
||||
|
||||
pub type FromSqlResult<T, K> = Result<(T, K), FromSqlError>;
|
||||
|
||||
pub trait FromSql: Sized {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
|
||||
}
|
||||
|
||||
impl FromSql for &str {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
|
||||
//~^ ERROR `impl` item signature doesn't match `trait` item signature
|
||||
value.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
println!("{}", "Hello World");
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
error: `impl` item signature doesn't match `trait` item signature
|
||||
--> $DIR/self-without-lifetime-constraint.rs:45:5
|
||||
|
|
||||
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
|
||||
| -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
|
||||
...
|
||||
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
|
||||
|
|
||||
= note: expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
|
||||
found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
|
||||
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
--> $DIR/self-without-lifetime-constraint.rs:41:60
|
||||
|
|
||||
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
|
||||
| ^^^^ consider borrowing this type parameter in the trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -19,8 +19,8 @@ note: ...so that the types are compatible
|
|||
|
|
||||
LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
|
||||
| ^^^^^^^^^^
|
||||
= note: expected `T1<'a>`
|
||||
found `T1<'_>`
|
||||
= note: expected `T1<'a>`
|
||||
found `T1<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
struct Article {
|
||||
proof_reader: ProofReader,
|
||||
}
|
||||
|
||||
struct ProofReader {
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub trait HaveRelationship<To> {
|
||||
fn get_relation(&self) -> To;
|
||||
}
|
||||
|
||||
impl HaveRelationship<&ProofReader> for Article {
|
||||
fn get_relation(&self) -> &ProofReader {
|
||||
//~^ ERROR `impl` item signature doesn't match `trait` item signature
|
||||
&self.proof_reader
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,19 @@
|
|||
error: `impl` item signature doesn't match `trait` item signature
|
||||
--> $DIR/trait-param-without-lifetime-constraint.rs:14:5
|
||||
|
|
||||
LL | fn get_relation(&self) -> To;
|
||||
| ----------------------------- expected `fn(&Article) -> &ProofReader`
|
||||
...
|
||||
LL | fn get_relation(&self) -> &ProofReader {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
|
||||
|
|
||||
= note: expected `fn(&Article) -> &ProofReader`
|
||||
found `fn(&Article) -> &ProofReader`
|
||||
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
--> $DIR/trait-param-without-lifetime-constraint.rs:10:31
|
||||
|
|
||||
LL | fn get_relation(&self) -> To;
|
||||
| ^^ consider borrowing this type parameter in the trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -23,8 +23,8 @@ note: ...so that the expression is assignable
|
|||
|
|
||||
LL | Box::new(items.iter())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
|
||||
found `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
|
||||
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
|
||||
found `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct Packed {
|
||||
data: &'static u32,
|
||||
}
|
||||
|
||||
const PACKED: Packed = Packed { data: &0 };
|
||||
|
||||
#[allow(safe_packed_borrows)]
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn allow_allow() {
|
||||
&PACKED.data; // allowed
|
||||
}
|
||||
|
||||
#[allow(safe_packed_borrows)]
|
||||
#[warn(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn allow_warn() {
|
||||
&PACKED.data; // allowed
|
||||
}
|
||||
|
||||
#[allow(safe_packed_borrows)]
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn allow_deny() {
|
||||
&PACKED.data; // allowed
|
||||
}
|
||||
|
||||
#[warn(safe_packed_borrows)]
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn warn_allow() {
|
||||
&PACKED.data; // allowed
|
||||
}
|
||||
|
||||
#[warn(safe_packed_borrows)]
|
||||
#[warn(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn warn_warn() {
|
||||
&PACKED.data; //~ WARN
|
||||
//~| WARNING this was previously accepted by the compiler but is being phased out
|
||||
}
|
||||
|
||||
#[warn(safe_packed_borrows)]
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn warn_deny() {
|
||||
&PACKED.data; //~ WARN
|
||||
//~| WARNING this was previously accepted by the compiler but is being phased out
|
||||
}
|
||||
|
||||
#[deny(safe_packed_borrows)]
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn deny_allow() {
|
||||
&PACKED.data; // allowed
|
||||
}
|
||||
|
||||
#[deny(safe_packed_borrows)]
|
||||
#[warn(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn deny_warn() {
|
||||
&PACKED.data; //~ WARN
|
||||
}
|
||||
|
||||
#[deny(safe_packed_borrows)]
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn deny_deny() {
|
||||
&PACKED.data; //~ ERROR
|
||||
//~| WARNING this was previously accepted by the compiler but is being phased out
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,60 @@
|
|||
warning: borrow of packed field is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:37:5
|
||||
|
|
||||
LL | &PACKED.data;
|
||||
| ^^^^^^^^^^^^ borrow of packed field
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:34:8
|
||||
|
|
||||
LL | #[warn(safe_packed_borrows)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
|
||||
= note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
|
||||
|
||||
warning: borrow of packed field is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:44:5
|
||||
|
|
||||
LL | &PACKED.data;
|
||||
| ^^^^^^^^^^^^ borrow of packed field
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:41:8
|
||||
|
|
||||
LL | #[warn(safe_packed_borrows)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
|
||||
= note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
|
||||
|
||||
warning: borrow of packed field is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:57:5
|
||||
|
|
||||
LL | &PACKED.data;
|
||||
| ^^^^^^^^^^^^ borrow of packed field
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:55:8
|
||||
|
|
||||
LL | #[warn(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
|
||||
|
||||
error: borrow of packed field is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:63:5
|
||||
|
|
||||
LL | &PACKED.data;
|
||||
| ^^^^^^^^^^^^ borrow of packed field
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:60:8
|
||||
|
|
||||
LL | #[deny(safe_packed_borrows)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
|
||||
= note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
|
||||
|
||||
error: aborting due to previous error; 3 warnings emitted
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![deny(unused_unsafe)]
|
||||
|
||||
unsafe fn unsf() {}
|
||||
const PTR: *const () = std::ptr::null();
|
||||
static mut VOID: () = ();
|
||||
|
||||
unsafe fn deny_level() {
|
||||
unsf();
|
||||
//~^ ERROR call to unsafe function is unsafe and requires unsafe block
|
||||
*PTR;
|
||||
//~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
|
||||
VOID = ();
|
||||
//~^ ERROR use of mutable static is unsafe and requires unsafe block
|
||||
}
|
||||
|
||||
// Check that `unsafe_op_in_unsafe_fn` works starting from the `warn` level.
|
||||
#[warn(unsafe_op_in_unsafe_fn)]
|
||||
#[deny(warnings)]
|
||||
unsafe fn warning_level() {
|
||||
unsf();
|
||||
//~^ ERROR call to unsafe function is unsafe and requires unsafe block
|
||||
*PTR;
|
||||
//~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
|
||||
VOID = ();
|
||||
//~^ ERROR use of mutable static is unsafe and requires unsafe block
|
||||
}
|
||||
|
||||
unsafe fn explicit_block() {
|
||||
// no error
|
||||
unsafe {
|
||||
unsf();
|
||||
*PTR;
|
||||
VOID = ();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn two_explicit_blocks() {
|
||||
unsafe { unsafe { unsf() } }
|
||||
//~^ ERROR unnecessary `unsafe` block
|
||||
}
|
||||
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn allow_level() {
|
||||
// lint allowed -> no error
|
||||
unsf();
|
||||
*PTR;
|
||||
VOID = ();
|
||||
|
||||
unsafe { unsf() }
|
||||
//~^ ERROR unnecessary `unsafe` block
|
||||
}
|
||||
|
||||
unsafe fn nested_allow_level() {
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
{
|
||||
// lint allowed -> no error
|
||||
unsf();
|
||||
*PTR;
|
||||
VOID = ();
|
||||
|
||||
unsafe { unsf() }
|
||||
//~^ ERROR unnecessary `unsafe` block
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsf();
|
||||
//~^ ERROR call to unsafe function is unsafe and requires unsafe block
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
{
|
||||
unsf();
|
||||
//~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:10:5
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
|
||||
|
|
||||
LL | #![deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
|
||||
|
|
||||
LL | *PTR;
|
||||
| ^^^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error: use of mutable static is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
|
||||
|
|
||||
LL | VOID = ();
|
||||
| ^^^^^^^^^ use of mutable static
|
||||
|
|
||||
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
|
||||
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:8
|
||||
|
|
||||
LL | #[deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
= note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5
|
||||
|
|
||||
LL | *PTR;
|
||||
| ^^^^ dereference of raw pointer
|
||||
|
|
||||
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
|
||||
error: use of mutable static is unsafe and requires unsafe block (error E0133)
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5
|
||||
|
|
||||
LL | VOID = ();
|
||||
| ^^^^^^^^^ use of mutable static
|
||||
|
|
||||
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:40:14
|
||||
|
|
||||
LL | unsafe { unsafe { unsf() } }
|
||||
| ------ ^^^^^^ unnecessary `unsafe` block
|
||||
| |
|
||||
| because it's nested under this `unsafe` block
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:3:9
|
||||
|
|
||||
LL | #![deny(unused_unsafe)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:51:5
|
||||
|
|
||||
LL | unsafe { unsf() }
|
||||
| ^^^^^^ unnecessary `unsafe` block
|
||||
|
||||
error: unnecessary `unsafe` block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:63:9
|
||||
|
|
||||
LL | unsafe { unsf() }
|
||||
| ^^^^^^ unnecessary `unsafe` block
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:69:5
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
|
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:9
|
||||
|
|
||||
LL | unsf();
|
||||
| ^^^^^^ call to unsafe function
|
||||
|
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0133`.
|
Loading…
Reference in New Issue