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:
bors 2020-05-29 23:43:20 +00:00
commit 0e9e408310
89 changed files with 1894 additions and 473 deletions

View File

@ -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 |

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)]

View File

@ -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,
{

View File

@ -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,
{

View File

@ -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;

View File

@ -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)

View File

@ -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();

View File

@ -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) {}

View File

@ -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 {

View File

@ -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
// -------------------------------------------------------------------------

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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
}

View File

@ -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())
}
}

View File

@ -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

View File

@ -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,

View File

@ -214,7 +214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let generics = tcx.generics_of(self.mir_def_id);
let param = generics.type_param(&param_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,
}
}

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}
}
};

View File

@ -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,
]
}

View File

@ -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,

View File

@ -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
}
}
}

View File

@ -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 {}
}

View File

@ -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);

View File

@ -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<_>>();

View File

@ -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)
}
}

View File

@ -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");

View File

@ -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

View File

@ -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]>

View File

@ -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() {

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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);
}

View File

@ -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() {}

View File

@ -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

View File

@ -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
|

View File

@ -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() {}

View File

@ -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`.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
|

View File

@ -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
|

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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
}
}

View File

@ -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`.