Auto merge of #144028 - samueltardieu:rollup-x6f9h8n, r=samueltardieu
Rollup of 12 pull requests Successful merges: - rust-lang/rust#142936 (rustdoc-json: Structured attributes) - rust-lang/rust#143355 (wrapping shift: remove first bitmask and table) - rust-lang/rust#143448 (remote-test-client: Exit code `128 + <signal-number>` instead of `3`) - rust-lang/rust#143692 (miri: fix out-of-bounds error for ptrs with negative offsets) - rust-lang/rust#143738 (Move several float tests to floats/mod.rs) - rust-lang/rust#143920 (Make more of codegen_llvm safe) - rust-lang/rust#143921 (Constify `Index` traits) - rust-lang/rust#143939 (Add 0323pin as maintainer of NetBSD targets, fix link to pkgsrc-wip and explain.) - rust-lang/rust#143948 (Update mdbook to 0.4.52) - rust-lang/rust#143957 (tidy: check for invalid file names) - rust-lang/rust#143968 (Add tracing to `InterpCx::fn_abi_of_instance/fn_abi_of_fn_ptr`) - rust-lang/rust#143990 (Add LocalKey<Cell>::update) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5795086bdf
85 changed files with 1140 additions and 1164 deletions
|
|
@ -879,9 +879,7 @@ pub(crate) fn codegen(
|
|||
.generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name);
|
||||
let thin_bc =
|
||||
module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode");
|
||||
unsafe {
|
||||
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc);
|
||||
}
|
||||
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -945,7 +943,7 @@ pub(crate) fn codegen(
|
|||
// binaries. So we must clone the module to produce the asm output
|
||||
// if we are also producing object code.
|
||||
let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj {
|
||||
unsafe { llvm::LLVMCloneModule(llmod) }
|
||||
llvm::LLVMCloneModule(llmod)
|
||||
} else {
|
||||
llmod
|
||||
};
|
||||
|
|
@ -1073,7 +1071,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) ->
|
|||
}
|
||||
|
||||
/// Embed the bitcode of an LLVM module for LTO in the LLVM module itself.
|
||||
unsafe fn embed_bitcode(
|
||||
fn embed_bitcode(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
llcx: &llvm::Context,
|
||||
llmod: &llvm::Module,
|
||||
|
|
@ -1115,43 +1113,40 @@ unsafe fn embed_bitcode(
|
|||
// Unfortunately, LLVM provides no way to set custom section flags. For ELF
|
||||
// and COFF we emit the sections using module level inline assembly for that
|
||||
// reason (see issue #90326 for historical background).
|
||||
unsafe {
|
||||
if cgcx.target_is_like_darwin
|
||||
|| cgcx.target_is_like_aix
|
||||
|| cgcx.target_arch == "wasm32"
|
||||
|| cgcx.target_arch == "wasm64"
|
||||
{
|
||||
// We don't need custom section flags, create LLVM globals.
|
||||
let llconst = common::bytes_in_context(llcx, bitcode);
|
||||
let llglobal =
|
||||
llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module");
|
||||
llvm::set_initializer(llglobal, llconst);
|
||||
|
||||
llvm::set_section(llglobal, bitcode_section_name(cgcx));
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
||||
if cgcx.target_is_like_darwin
|
||||
|| cgcx.target_is_like_aix
|
||||
|| cgcx.target_arch == "wasm32"
|
||||
|| cgcx.target_arch == "wasm64"
|
||||
{
|
||||
// We don't need custom section flags, create LLVM globals.
|
||||
let llconst = common::bytes_in_context(llcx, bitcode);
|
||||
let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module");
|
||||
llvm::set_initializer(llglobal, llconst);
|
||||
|
||||
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
|
||||
let llglobal =
|
||||
llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline");
|
||||
llvm::set_initializer(llglobal, llconst);
|
||||
let section = if cgcx.target_is_like_darwin {
|
||||
c"__LLVM,__cmdline"
|
||||
} else if cgcx.target_is_like_aix {
|
||||
c".info"
|
||||
} else {
|
||||
c".llvmcmd"
|
||||
};
|
||||
llvm::set_section(llglobal, section);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(llglobal, bitcode_section_name(cgcx));
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
||||
|
||||
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
|
||||
let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline");
|
||||
llvm::set_initializer(llglobal, llconst);
|
||||
let section = if cgcx.target_is_like_darwin {
|
||||
c"__LLVM,__cmdline"
|
||||
} else if cgcx.target_is_like_aix {
|
||||
c".info"
|
||||
} else {
|
||||
// We need custom section flags, so emit module-level inline assembly.
|
||||
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
|
||||
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
|
||||
llvm::append_module_inline_asm(llmod, &asm);
|
||||
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
|
||||
llvm::append_module_inline_asm(llmod, &asm);
|
||||
}
|
||||
c".llvmcmd"
|
||||
};
|
||||
llvm::set_section(llglobal, section);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
} else {
|
||||
// We need custom section flags, so emit module-level inline assembly.
|
||||
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
|
||||
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
|
||||
llvm::append_module_inline_asm(llmod, &asm);
|
||||
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
|
||||
llvm::append_module_inline_asm(llmod, &asm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -302,10 +302,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let id_str = "branch_weights";
|
||||
let id = unsafe {
|
||||
llvm::LLVMMDStringInContext2(self.cx.llcx, id_str.as_ptr().cast(), id_str.len())
|
||||
};
|
||||
let id = self.cx.create_metadata(b"branch_weights");
|
||||
|
||||
// For switch instructions with 2 targets, the `llvm.expect` intrinsic is used.
|
||||
// This function handles switch instructions with more than 2 targets and it needs to
|
||||
|
|
@ -637,17 +634,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
} else if place.layout.is_llvm_immediate() {
|
||||
let mut const_llval = None;
|
||||
let llty = place.layout.llvm_type(self);
|
||||
unsafe {
|
||||
if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) {
|
||||
if llvm::LLVMIsGlobalConstant(global) == llvm::True {
|
||||
if let Some(init) = llvm::LLVMGetInitializer(global) {
|
||||
if self.val_ty(init) == llty {
|
||||
const_llval = Some(init);
|
||||
}
|
||||
if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) {
|
||||
if llvm::LLVMIsGlobalConstant(global) == llvm::True {
|
||||
if let Some(init) = llvm::LLVMGetInitializer(global) {
|
||||
if self.val_ty(init) == llty {
|
||||
const_llval = Some(init);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let llval = const_llval.unwrap_or_else(|| {
|
||||
let load = self.load(llty, place.val.llval, place.val.align);
|
||||
if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr {
|
||||
|
|
@ -1721,7 +1717,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
} else {
|
||||
cfi::typeid_for_fnabi(self.tcx, fn_abi, options)
|
||||
};
|
||||
let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
|
||||
let typeid_metadata = self.cx.create_metadata(typeid.as_bytes());
|
||||
let dbg_loc = self.get_dbg_loc();
|
||||
|
||||
// Test whether the function pointer is associated with the type identifier using the
|
||||
|
|
|
|||
|
|
@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>(
|
|||
outer_pos = 1;
|
||||
}
|
||||
|
||||
let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
|
||||
let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
|
||||
let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
|
||||
let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap();
|
||||
let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
|
||||
let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap();
|
||||
let enzyme_const = cx.create_metadata(b"enzyme_const");
|
||||
let enzyme_out = cx.create_metadata(b"enzyme_out");
|
||||
let enzyme_dup = cx.create_metadata(b"enzyme_dup");
|
||||
let enzyme_dupv = cx.create_metadata(b"enzyme_dupv");
|
||||
let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed");
|
||||
let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv");
|
||||
|
||||
while activity_pos < inputs.len() {
|
||||
let diff_activity = inputs[activity_pos as usize];
|
||||
|
|
@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>(
|
|||
let mut args = Vec::with_capacity(num_args as usize + 1);
|
||||
args.push(fn_to_diff);
|
||||
|
||||
let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap();
|
||||
let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return");
|
||||
if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) {
|
||||
args.push(cx.get_metadata_value(enzyme_primal_ret));
|
||||
}
|
||||
if attrs.width > 1 {
|
||||
let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap();
|
||||
let enzyme_width = cx.create_metadata(b"enzyme_width");
|
||||
args.push(cx.get_metadata_value(enzyme_width));
|
||||
args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,10 +215,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
|
|||
bug!("symbol `{}` is already defined", sym);
|
||||
});
|
||||
llvm::set_initializer(g, sc);
|
||||
unsafe {
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
|
||||
}
|
||||
|
||||
llvm::set_global_constant(g, true);
|
||||
llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global);
|
||||
|
||||
llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
|
||||
// Cast to default address space if globals are in a different addrspace
|
||||
let g = self.const_pointercast(g, self.type_ptr());
|
||||
|
|
|
|||
|
|
@ -17,13 +17,12 @@ use rustc_middle::ty::{self, Instance};
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::common::CodegenCx;
|
||||
use crate::errors::SymbolAlreadyDefined;
|
||||
use crate::llvm::{self, True};
|
||||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
use crate::{base, debuginfo};
|
||||
use crate::{base, debuginfo, llvm};
|
||||
|
||||
pub(crate) fn const_alloc_to_llvm<'ll>(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
|
|
@ -247,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
};
|
||||
llvm::set_initializer(gv, cv);
|
||||
set_global_alignment(self, gv, align);
|
||||
llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
|
||||
llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global);
|
||||
gv
|
||||
}
|
||||
|
||||
|
|
@ -272,9 +271,8 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
return gv;
|
||||
}
|
||||
let gv = self.static_addr_of_mut(cv, align, kind);
|
||||
unsafe {
|
||||
llvm::LLVMSetGlobalConstant(gv, True);
|
||||
}
|
||||
llvm::set_global_constant(gv, true);
|
||||
|
||||
self.const_globals.borrow_mut().insert(cv, gv);
|
||||
gv
|
||||
}
|
||||
|
|
@ -398,149 +396,140 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
}
|
||||
|
||||
fn codegen_static_item(&mut self, def_id: DefId) {
|
||||
unsafe {
|
||||
assert!(
|
||||
llvm::LLVMGetInitializer(
|
||||
self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap()
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
let attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
assert!(
|
||||
llvm::LLVMGetInitializer(
|
||||
self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap()
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
let attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else {
|
||||
// Error has already been reported
|
||||
return;
|
||||
};
|
||||
let alloc = alloc.inner();
|
||||
let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else {
|
||||
// Error has already been reported
|
||||
return;
|
||||
};
|
||||
let alloc = alloc.inner();
|
||||
|
||||
let val_llty = self.val_ty(v);
|
||||
let val_llty = self.val_ty(v);
|
||||
|
||||
let g = self.get_static_inner(def_id, val_llty);
|
||||
let llty = self.get_type_of_global(g);
|
||||
let g = self.get_static_inner(def_id, val_llty);
|
||||
let llty = self.get_type_of_global(g);
|
||||
|
||||
let g = if val_llty == llty {
|
||||
g
|
||||
} else {
|
||||
// codegen_static_initializer creates the global value just from the
|
||||
// `Allocation` data by generating one big struct value that is just
|
||||
// all the bytes and pointers after each other. This will almost never
|
||||
// match the type that the static was declared with. Unfortunately
|
||||
// we can't just LLVMConstBitCast our way out of it because that has very
|
||||
// specific rules on what can be cast. So instead of adding a new way to
|
||||
// generate static initializers that match the static's type, we picked
|
||||
// the easier option and retroactively change the type of the static item itself.
|
||||
let name = llvm::get_value_name(g);
|
||||
llvm::set_value_name(g, b"");
|
||||
let g = if val_llty == llty {
|
||||
g
|
||||
} else {
|
||||
// codegen_static_initializer creates the global value just from the
|
||||
// `Allocation` data by generating one big struct value that is just
|
||||
// all the bytes and pointers after each other. This will almost never
|
||||
// match the type that the static was declared with. Unfortunately
|
||||
// we can't just LLVMConstBitCast our way out of it because that has very
|
||||
// specific rules on what can be cast. So instead of adding a new way to
|
||||
// generate static initializers that match the static's type, we picked
|
||||
// the easier option and retroactively change the type of the static item itself.
|
||||
let name = String::from_utf8(llvm::get_value_name(g))
|
||||
.expect("we declare our statics with a utf8-valid name");
|
||||
llvm::set_value_name(g, b"");
|
||||
|
||||
let linkage = llvm::get_linkage(g);
|
||||
let visibility = llvm::get_visibility(g);
|
||||
let linkage = llvm::get_linkage(g);
|
||||
let visibility = llvm::get_visibility(g);
|
||||
|
||||
let new_g = llvm::LLVMRustGetOrInsertGlobal(
|
||||
self.llmod,
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
val_llty,
|
||||
);
|
||||
let new_g = self.declare_global(&name, val_llty);
|
||||
|
||||
llvm::set_linkage(new_g, linkage);
|
||||
llvm::set_visibility(new_g, visibility);
|
||||
llvm::set_linkage(new_g, linkage);
|
||||
llvm::set_visibility(new_g, visibility);
|
||||
|
||||
// The old global has had its name removed but is returned by
|
||||
// get_static since it is in the instance cache. Provide an
|
||||
// alternative lookup that points to the new global so that
|
||||
// global_asm! can compute the correct mangled symbol name
|
||||
// for the global.
|
||||
self.renamed_statics.borrow_mut().insert(def_id, new_g);
|
||||
// The old global has had its name removed but is returned by
|
||||
// get_static since it is in the instance cache. Provide an
|
||||
// alternative lookup that points to the new global so that
|
||||
// global_asm! can compute the correct mangled symbol name
|
||||
// for the global.
|
||||
self.renamed_statics.borrow_mut().insert(def_id, new_g);
|
||||
|
||||
// To avoid breaking any invariants, we leave around the old
|
||||
// global for the moment; we'll replace all references to it
|
||||
// with the new global later. (See base::codegen_backend.)
|
||||
self.statics_to_rauw.borrow_mut().push((g, new_g));
|
||||
new_g
|
||||
};
|
||||
set_global_alignment(self, g, alloc.align);
|
||||
llvm::set_initializer(g, v);
|
||||
// To avoid breaking any invariants, we leave around the old
|
||||
// global for the moment; we'll replace all references to it
|
||||
// with the new global later. (See base::codegen_backend.)
|
||||
self.statics_to_rauw.borrow_mut().push((g, new_g));
|
||||
new_g
|
||||
};
|
||||
set_global_alignment(self, g, alloc.align);
|
||||
llvm::set_initializer(g, v);
|
||||
|
||||
self.assume_dso_local(g, true);
|
||||
self.assume_dso_local(g, true);
|
||||
|
||||
// Forward the allocation's mutability (picked by the const interner) to LLVM.
|
||||
if alloc.mutability.is_not() {
|
||||
llvm::LLVMSetGlobalConstant(g, llvm::True);
|
||||
}
|
||||
// Forward the allocation's mutability (picked by the const interner) to LLVM.
|
||||
if alloc.mutability.is_not() {
|
||||
llvm::set_global_constant(g, true);
|
||||
}
|
||||
|
||||
debuginfo::build_global_var_di_node(self, def_id, g);
|
||||
debuginfo::build_global_var_di_node(self, def_id, g);
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
|
||||
llvm::set_thread_local_mode(g, self.tls_model);
|
||||
}
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
|
||||
llvm::set_thread_local_mode(g, self.tls_model);
|
||||
}
|
||||
|
||||
// Wasm statics with custom link sections get special treatment as they
|
||||
// go into custom sections of the wasm executable. The exception to this
|
||||
// is the `.init_array` section which are treated specially by the wasm linker.
|
||||
if self.tcx.sess.target.is_like_wasm
|
||||
&& attrs
|
||||
.link_section
|
||||
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
if let Some(section) = attrs.link_section {
|
||||
let section = llvm::LLVMMDStringInContext2(
|
||||
self.llcx,
|
||||
section.as_str().as_c_char_ptr(),
|
||||
section.as_str().len(),
|
||||
);
|
||||
assert!(alloc.provenance().ptrs().is_empty());
|
||||
// Wasm statics with custom link sections get special treatment as they
|
||||
// go into custom sections of the wasm executable. The exception to this
|
||||
// is the `.init_array` section which are treated specially by the wasm linker.
|
||||
if self.tcx.sess.target.is_like_wasm
|
||||
&& attrs
|
||||
.link_section
|
||||
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
if let Some(section) = attrs.link_section {
|
||||
let section = self.create_metadata(section.as_str().as_bytes());
|
||||
assert!(alloc.provenance().ptrs().is_empty());
|
||||
|
||||
// The `inspect` method is okay here because we checked for provenance, and
|
||||
// because we are doing this access to inspect the final interpreter state (not
|
||||
// as part of the interpreter execution).
|
||||
let bytes =
|
||||
alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
|
||||
let alloc =
|
||||
llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len());
|
||||
let data = [section, alloc];
|
||||
let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
|
||||
let val = self.get_metadata_value(meta);
|
||||
// The `inspect` method is okay here because we checked for provenance, and
|
||||
// because we are doing this access to inspect the final interpreter state (not
|
||||
// as part of the interpreter execution).
|
||||
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
|
||||
let alloc = self.create_metadata(bytes);
|
||||
let data = [section, alloc];
|
||||
let meta =
|
||||
unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) };
|
||||
let val = self.get_metadata_value(meta);
|
||||
unsafe {
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
self.llmod,
|
||||
c"wasm.custom_sections".as_ptr(),
|
||||
val,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
base::set_link_section(g, attrs);
|
||||
)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
base::set_link_section(g, attrs);
|
||||
}
|
||||
|
||||
base::set_variable_sanitizer_attrs(g, attrs);
|
||||
base::set_variable_sanitizer_attrs(g, attrs);
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) {
|
||||
// `USED` and `USED_LINKER` can't be used together.
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) {
|
||||
// `USED` and `USED_LINKER` can't be used together.
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
|
||||
|
||||
// The semantics of #[used] in Rust only require the symbol to make it into the
|
||||
// object file. It is explicitly allowed for the linker to strip the symbol if it
|
||||
// is dead, which means we are allowed to use `llvm.compiler.used` instead of
|
||||
// `llvm.used` here.
|
||||
//
|
||||
// Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
|
||||
// sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
|
||||
// in the handling of `.init_array` (the static constructor list) in versions of
|
||||
// the gold linker (prior to the one released with binutils 2.36).
|
||||
//
|
||||
// That said, we only ever emit these when `#[used(compiler)]` is explicitly
|
||||
// requested. This is to avoid similar breakage on other targets, in particular
|
||||
// MachO targets have *their* static constructor lists broken if `llvm.compiler.used`
|
||||
// is emitted rather than `llvm.used`. However, that check happens when assigning
|
||||
// the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to
|
||||
// take care of it here.
|
||||
self.add_compiler_used_global(g);
|
||||
}
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
|
||||
// `USED` and `USED_LINKER` can't be used together.
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER));
|
||||
// The semantics of #[used] in Rust only require the symbol to make it into the
|
||||
// object file. It is explicitly allowed for the linker to strip the symbol if it
|
||||
// is dead, which means we are allowed to use `llvm.compiler.used` instead of
|
||||
// `llvm.used` here.
|
||||
//
|
||||
// Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
|
||||
// sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
|
||||
// in the handling of `.init_array` (the static constructor list) in versions of
|
||||
// the gold linker (prior to the one released with binutils 2.36).
|
||||
//
|
||||
// That said, we only ever emit these when `#[used(compiler)]` is explicitly
|
||||
// requested. This is to avoid similar breakage on other targets, in particular
|
||||
// MachO targets have *their* static constructor lists broken if `llvm.compiler.used`
|
||||
// is emitted rather than `llvm.used`. However, that check happens when assigning
|
||||
// the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to
|
||||
// take care of it here.
|
||||
self.add_compiler_used_global(g);
|
||||
}
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
|
||||
// `USED` and `USED_LINKER` can't be used together.
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER));
|
||||
|
||||
self.add_used_global(g);
|
||||
}
|
||||
self.add_used_global(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ use smallvec::SmallVec;
|
|||
|
||||
use crate::back::write::to_llvm_code_model;
|
||||
use crate::callee::get_fn;
|
||||
use crate::common::AsCCharPtr;
|
||||
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
|
||||
use crate::llvm::Metadata;
|
||||
use crate::type_::Type;
|
||||
|
|
@ -169,6 +168,8 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
let mod_name = SmallCStr::new(mod_name);
|
||||
let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) };
|
||||
|
||||
let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size());
|
||||
|
||||
let mut target_data_layout = sess.target.data_layout.to_string();
|
||||
let llvm_version = llvm_util::get_version();
|
||||
|
||||
|
|
@ -473,18 +474,14 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
#[allow(clippy::option_env_unwrap)]
|
||||
let rustc_producer =
|
||||
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
|
||||
let name_metadata = unsafe {
|
||||
llvm::LLVMMDStringInContext2(
|
||||
llcx,
|
||||
rustc_producer.as_c_char_ptr(),
|
||||
rustc_producer.as_bytes().len(),
|
||||
)
|
||||
};
|
||||
|
||||
let name_metadata = cx.create_metadata(rustc_producer.as_bytes());
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
llmod,
|
||||
c"llvm.ident".as_ptr(),
|
||||
&llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)),
|
||||
&cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -698,10 +695,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> {
|
||||
Some(unsafe {
|
||||
pub(crate) fn create_metadata(&self, name: &[u8]) -> &'ll Metadata {
|
||||
unsafe {
|
||||
llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_functions(&self) -> Vec<&'ll Value> {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
|
|||
llvm::set_section(section_var, c".debug_gdb_scripts");
|
||||
llvm::set_initializer(section_var, cx.const_bytes(section_contents));
|
||||
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
|
||||
llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
|
||||
llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global);
|
||||
llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
|
||||
// This should make sure that the whole section is not larger than
|
||||
// the string it contains. Otherwise we get a warning from GDB.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
|
|||
use std::sync::Arc;
|
||||
use std::{iter, ptr};
|
||||
|
||||
use libc::{c_char, c_longlong, c_uint};
|
||||
use libc::{c_longlong, c_uint};
|
||||
use rustc_abi::{Align, Size};
|
||||
use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
|
|
@ -1582,13 +1582,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
|||
};
|
||||
|
||||
let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
|
||||
let typeid = cx.create_metadata(trait_ref_typeid.as_bytes());
|
||||
|
||||
unsafe {
|
||||
let typeid = llvm::LLVMMDStringInContext2(
|
||||
cx.llcx,
|
||||
trait_ref_typeid.as_ptr() as *const c_char,
|
||||
trait_ref_typeid.as_bytes().len(),
|
||||
);
|
||||
let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
vtable,
|
||||
|
|
@ -1630,7 +1626,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
|
|||
// When full debuginfo is enabled, we want to try and prevent vtables from being
|
||||
// merged. Otherwise debuggers will have a hard time mapping from dyn pointer
|
||||
// to concrete type.
|
||||
llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No);
|
||||
llvm::set_unnamed_address(vtable, llvm::UnnamedAddr::No);
|
||||
|
||||
let vtable_name =
|
||||
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub(crate) fn declare_simple_fn<'ll>(
|
|||
};
|
||||
|
||||
llvm::SetFunctionCallConv(llfn, callconv);
|
||||
llvm::SetUnnamedAddress(llfn, unnamed);
|
||||
llvm::set_unnamed_address(llfn, unnamed);
|
||||
llvm::set_visibility(llfn, visibility);
|
||||
|
||||
llfn
|
||||
|
|
@ -176,7 +176,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
{
|
||||
let typeid = cfi::typeid_for_instance(self.tcx, instance, options);
|
||||
if typeids.insert(typeid.clone()) {
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
self.add_type_metadata(llfn, typeid.as_bytes());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -189,7 +189,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
.map(cfi::TypeIdOptions::from_iter)
|
||||
{
|
||||
let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
self.add_type_metadata(llfn, typeid.as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1009,7 +1009,7 @@ unsafe extern "C" {
|
|||
ModuleID: *const c_char,
|
||||
C: &Context,
|
||||
) -> &Module;
|
||||
pub(crate) fn LLVMCloneModule(M: &Module) -> &Module;
|
||||
pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module;
|
||||
|
||||
/// Data layout. See Module::getDataLayout.
|
||||
pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char;
|
||||
|
|
@ -1168,18 +1168,18 @@ unsafe extern "C" {
|
|||
pub(crate) fn LLVMGlobalGetValueType(Global: &Value) -> &Type;
|
||||
|
||||
// Operations on global variables
|
||||
pub(crate) fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
|
||||
pub(crate) safe fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
|
||||
pub(crate) fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
|
||||
pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
|
||||
pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
|
||||
pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
|
||||
pub(crate) fn LLVMDeleteGlobal(GlobalVar: &Value);
|
||||
pub(crate) fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
|
||||
pub(crate) safe fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
|
||||
pub(crate) fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value);
|
||||
pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
|
||||
pub(crate) safe fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
|
||||
pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
|
||||
pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
|
||||
pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
|
||||
pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
|
||||
pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
|
||||
pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
|
||||
|
||||
// Operations on attributes
|
||||
|
|
@ -1718,7 +1718,7 @@ unsafe extern "C" {
|
|||
|
||||
pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
|
||||
|
||||
pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
|
||||
pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
|
||||
|
||||
pub(crate) fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
|
||||
|
||||
|
|
|
|||
|
|
@ -217,10 +217,8 @@ pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) {
|
|||
set_comdat(llmod, val, &name);
|
||||
}
|
||||
|
||||
pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
|
||||
unsafe {
|
||||
LLVMSetUnnamedAddress(global, unnamed);
|
||||
}
|
||||
pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) {
|
||||
LLVMSetUnnamedAddress(global, unnamed);
|
||||
}
|
||||
|
||||
pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
|
||||
|
|
@ -260,9 +258,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) {
|
|||
}
|
||||
|
||||
pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) {
|
||||
unsafe {
|
||||
LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
|
||||
}
|
||||
LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
|
||||
}
|
||||
|
||||
pub(crate) fn get_linkage(llglobal: &Value) -> Linkage {
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@ impl CodegenCx<'_, '_> {
|
|||
}
|
||||
|
||||
// Thread-local variables generally don't support copy relocations.
|
||||
let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) }
|
||||
.is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True);
|
||||
let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
|
||||
.is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True);
|
||||
if is_thread_local_var {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::borrow::Borrow;
|
|||
use std::hash::{Hash, Hasher};
|
||||
use std::{fmt, ptr};
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
use libc::c_uint;
|
||||
use rustc_abi::{AddressSpace, Align, Integer, Reg, Size};
|
||||
use rustc_codegen_ssa::common::TypeKind;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
|
|
@ -298,8 +298,8 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
fn add_type_metadata(&self, function: &'ll Value, typeid: String) {
|
||||
let typeid_metadata = self.typeid_metadata(typeid).unwrap();
|
||||
fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
|
||||
let typeid_metadata = self.create_metadata(typeid);
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
|
|
@ -310,8 +310,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
|
||||
let typeid_metadata = self.typeid_metadata(typeid).unwrap();
|
||||
fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
|
||||
let typeid_metadata = self.create_metadata(typeid);
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
|
|
@ -322,10 +322,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> {
|
||||
Some(unsafe {
|
||||
llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len())
|
||||
})
|
||||
fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> {
|
||||
Some(self.create_metadata(typeid))
|
||||
}
|
||||
|
||||
fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
&& bx.cx().sess().lto() == Lto::Fat
|
||||
{
|
||||
if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) {
|
||||
let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap();
|
||||
let typeid =
|
||||
bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap();
|
||||
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
||||
return func;
|
||||
} else if nonnull {
|
||||
|
|
|
|||
|
|
@ -154,9 +154,9 @@ pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes {
|
|||
// For backends that support CFI using type membership (i.e., testing whether a given pointer is
|
||||
// associated with a type identifier).
|
||||
pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes {
|
||||
fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {}
|
||||
fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {}
|
||||
fn typeid_metadata(&self, _typeid: String) -> Option<Self::Metadata> {
|
||||
fn add_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {}
|
||||
fn set_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {}
|
||||
fn typeid_metadata(&self, _typeid: &[u8]) -> Option<Self::Metadata> {
|
||||
None
|
||||
}
|
||||
fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {}
|
||||
|
|
|
|||
|
|
@ -296,19 +296,22 @@ const_eval_pointer_arithmetic_overflow =
|
|||
overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
|
||||
|
||||
const_eval_pointer_out_of_bounds =
|
||||
{const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg ->
|
||||
[false] {$alloc_size_minus_ptr_offset ->
|
||||
[0] is at or beyond the end of the allocation of size {$alloc_size ->
|
||||
[1] 1 byte
|
||||
*[x] {$alloc_size} bytes
|
||||
{const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg ->
|
||||
[true] points to before the beginning of the allocation
|
||||
*[false] {$inbounds_size_is_neg ->
|
||||
[false] {$alloc_size_minus_ptr_offset ->
|
||||
[0] is at or beyond the end of the allocation of size {$alloc_size ->
|
||||
[1] 1 byte
|
||||
*[x] {$alloc_size} bytes
|
||||
}
|
||||
[1] is only 1 byte from the end of the allocation
|
||||
*[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
|
||||
}
|
||||
*[true] {$ptr_offset_abs ->
|
||||
[0] is at the beginning of the allocation
|
||||
*[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
|
||||
}
|
||||
[1] is only 1 byte from the end of the allocation
|
||||
*[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
|
||||
}
|
||||
*[true] {$ptr_offset_abs ->
|
||||
[0] is at the beginning of the allocation
|
||||
*[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const_eval_pointer_use_after_free =
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::borrow::Cow;
|
|||
use either::{Left, Right};
|
||||
use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout};
|
||||
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::sym;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{
|
||||
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
|
||||
TyAndLayout,
|
||||
self, FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf,
|
||||
LayoutOfHelpers, TyAndLayout,
|
||||
};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
|
||||
use rustc_middle::{mir, span_bug};
|
||||
|
|
@ -92,20 +92,6 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
/// This inherent method takes priority over the trait method with the same name in LayoutOf,
|
||||
/// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span.
|
||||
/// See [LayoutOf::layout_of] for the original documentation.
|
||||
#[inline(always)]
|
||||
pub fn layout_of(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
) -> <InterpCx<'tcx, M> as LayoutOfHelpers<'tcx>>::LayoutOfResult {
|
||||
let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind());
|
||||
LayoutOf::layout_of(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
|
||||
type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>;
|
||||
|
||||
|
|
@ -121,6 +107,43 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
/// This inherent method takes priority over the trait method with the same name in LayoutOf,
|
||||
/// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span.
|
||||
/// See [LayoutOf::layout_of] for the original documentation.
|
||||
#[inline(always)]
|
||||
pub fn layout_of(&self, ty: Ty<'tcx>) -> <Self as LayoutOfHelpers<'tcx>>::LayoutOfResult {
|
||||
let _span = enter_trace_span!(M, "InterpCx::layout_of", ty = ?ty.kind());
|
||||
LayoutOf::layout_of(self, ty)
|
||||
}
|
||||
|
||||
/// This inherent method takes priority over the trait method with the same name in FnAbiOf,
|
||||
/// and allows wrapping the actual [FnAbiOf::fn_abi_of_fn_ptr] with a tracing span.
|
||||
/// See [FnAbiOf::fn_abi_of_fn_ptr] for the original documentation.
|
||||
#[inline(always)]
|
||||
pub fn fn_abi_of_fn_ptr(
|
||||
&self,
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
extra_args: &'tcx ty::List<Ty<'tcx>>,
|
||||
) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
|
||||
let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_fn_ptr", ?sig, ?extra_args);
|
||||
FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args)
|
||||
}
|
||||
|
||||
/// This inherent method takes priority over the trait method with the same name in FnAbiOf,
|
||||
/// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance] with a tracing span.
|
||||
/// See [FnAbiOf::fn_abi_of_instance] for the original documentation.
|
||||
#[inline(always)]
|
||||
pub fn fn_abi_of_instance(
|
||||
&self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
extra_args: &'tcx ty::List<Ty<'tcx>>,
|
||||
) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
|
||||
let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_instance", ?instance, ?extra_args);
|
||||
FnAbiOf::fn_abi_of_instance(self, instance, extra_args)
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value.
|
||||
/// This test should be symmetric, as it is primarily about layout compatibility.
|
||||
pub(super) fn mir_assign_valid_types<'tcx>(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
use either::Either;
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
|
|
|||
|
|
@ -374,9 +374,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] {
|
|||
}
|
||||
|
||||
#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
|
||||
impl<T, I, const N: usize> Index<I> for [T; N]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I, const N: usize> const Index<I> for [T; N]
|
||||
where
|
||||
[T]: Index<I>,
|
||||
[T]: ~const Index<I>,
|
||||
{
|
||||
type Output = <[T] as Index<I>>::Output;
|
||||
|
||||
|
|
@ -387,9 +388,10 @@ where
|
|||
}
|
||||
|
||||
#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
|
||||
impl<T, I, const N: usize> IndexMut<I> for [T; N]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I, const N: usize> const IndexMut<I> for [T; N]
|
||||
where
|
||||
[T]: IndexMut<I>,
|
||||
[T]: ~const IndexMut<I>,
|
||||
{
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
||||
|
|
|
|||
|
|
@ -94,9 +94,9 @@ macro_rules! sh_impl_signed {
|
|||
#[inline]
|
||||
fn shl(self, other: $f) -> Wrapping<$t> {
|
||||
if other < 0 {
|
||||
Wrapping(self.0.wrapping_shr((-other & self::shift_max::$t as $f) as u32))
|
||||
Wrapping(self.0.wrapping_shr(-other as u32))
|
||||
} else {
|
||||
Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
|
||||
Wrapping(self.0.wrapping_shl(other as u32))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -119,9 +119,9 @@ macro_rules! sh_impl_signed {
|
|||
#[inline]
|
||||
fn shr(self, other: $f) -> Wrapping<$t> {
|
||||
if other < 0 {
|
||||
Wrapping(self.0.wrapping_shl((-other & self::shift_max::$t as $f) as u32))
|
||||
Wrapping(self.0.wrapping_shl(-other as u32))
|
||||
} else {
|
||||
Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
|
||||
Wrapping(self.0.wrapping_shr(other as u32))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -147,7 +147,7 @@ macro_rules! sh_impl_unsigned {
|
|||
|
||||
#[inline]
|
||||
fn shl(self, other: $f) -> Wrapping<$t> {
|
||||
Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
|
||||
Wrapping(self.0.wrapping_shl(other as u32))
|
||||
}
|
||||
}
|
||||
forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
|
||||
|
|
@ -168,7 +168,7 @@ macro_rules! sh_impl_unsigned {
|
|||
|
||||
#[inline]
|
||||
fn shr(self, other: $f) -> Wrapping<$t> {
|
||||
Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
|
||||
Wrapping(self.0.wrapping_shr(other as u32))
|
||||
}
|
||||
}
|
||||
forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
|
||||
|
|
@ -1052,39 +1052,3 @@ macro_rules! wrapping_int_impl_unsigned {
|
|||
}
|
||||
|
||||
wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 }
|
||||
|
||||
mod shift_max {
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
mod platform {
|
||||
pub(crate) const usize: u32 = super::u16;
|
||||
pub(crate) const isize: u32 = super::i16;
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
mod platform {
|
||||
pub(crate) const usize: u32 = super::u32;
|
||||
pub(crate) const isize: u32 = super::i32;
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod platform {
|
||||
pub(crate) const usize: u32 = super::u64;
|
||||
pub(crate) const isize: u32 = super::i64;
|
||||
}
|
||||
|
||||
pub(super) const i8: u32 = (1 << 3) - 1;
|
||||
pub(super) const i16: u32 = (1 << 4) - 1;
|
||||
pub(super) const i32: u32 = (1 << 5) - 1;
|
||||
pub(super) const i64: u32 = (1 << 6) - 1;
|
||||
pub(super) const i128: u32 = (1 << 7) - 1;
|
||||
pub(super) use self::platform::isize;
|
||||
|
||||
pub(super) const u8: u32 = i8;
|
||||
pub(super) const u16: u32 = i16;
|
||||
pub(super) const u32: u32 = i32;
|
||||
pub(super) const u64: u32 = i64;
|
||||
pub(super) const u128: u32 = i128;
|
||||
pub(super) use self::platform::usize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@
|
|||
#[doc(alias = "]")]
|
||||
#[doc(alias = "[")]
|
||||
#[doc(alias = "[]")]
|
||||
#[const_trait]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub trait Index<Idx: ?Sized> {
|
||||
/// The returned type after indexing.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -165,7 +167,9 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
|
|||
#[doc(alias = "[")]
|
||||
#[doc(alias = "]")]
|
||||
#[doc(alias = "[]")]
|
||||
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[const_trait]
|
||||
pub trait IndexMut<Idx: ?Sized>: ~const Index<Idx> {
|
||||
/// Performs the mutable indexing (`container[index]`) operation.
|
||||
///
|
||||
/// # Panics
|
||||
|
|
|
|||
|
|
@ -1524,10 +1524,11 @@ impl<T> *const [T] {
|
|||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "slice_ptr_get", issue = "74265")]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[inline]
|
||||
pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
|
||||
pub const unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
|
||||
where
|
||||
I: SliceIndex<[T]>,
|
||||
I: ~const SliceIndex<[T]>,
|
||||
{
|
||||
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
|
||||
unsafe { index.get_unchecked(self) }
|
||||
|
|
|
|||
|
|
@ -1881,10 +1881,11 @@ impl<T> *mut [T] {
|
|||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "slice_ptr_get", issue = "74265")]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
|
||||
pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
|
||||
where
|
||||
I: SliceIndex<[T]>,
|
||||
I: ~const SliceIndex<[T]>,
|
||||
{
|
||||
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
|
||||
unsafe { index.get_unchecked_mut(self) }
|
||||
|
|
|
|||
|
|
@ -1597,10 +1597,11 @@ impl<T> NonNull<[T]> {
|
|||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "slice_ptr_get", issue = "74265")]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[inline]
|
||||
pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
|
||||
pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
|
||||
where
|
||||
I: SliceIndex<[T]>,
|
||||
I: ~const SliceIndex<[T]>,
|
||||
{
|
||||
// SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
|
||||
// As a consequence, the resulting pointer cannot be null.
|
||||
|
|
|
|||
|
|
@ -186,14 +186,17 @@ impl<T> IntoBounds<T> for Range<T> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<Range<T>> for legacy::Range<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<Range<T>> for legacy::Range<T> {
|
||||
#[inline]
|
||||
fn from(value: Range<T>) -> Self {
|
||||
Self { start: value.start, end: value.end }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<legacy::Range<T>> for Range<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<legacy::Range<T>> for Range<T> {
|
||||
#[inline]
|
||||
fn from(value: legacy::Range<T>) -> Self {
|
||||
Self { start: value.start, end: value.end }
|
||||
|
|
@ -362,7 +365,8 @@ impl<T> IntoBounds<T> for RangeInclusive<T> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
|
||||
#[inline]
|
||||
fn from(value: RangeInclusive<T>) -> Self {
|
||||
Self::new(value.start, value.end)
|
||||
|
|
@ -506,14 +510,16 @@ impl<T> IntoBounds<T> for RangeFrom<T> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<RangeFrom<T>> for legacy::RangeFrom<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> {
|
||||
#[inline]
|
||||
fn from(value: RangeFrom<T>) -> Self {
|
||||
Self { start: value.start }
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<legacy::RangeFrom<T>> for RangeFrom<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> {
|
||||
#[inline]
|
||||
fn from(value: legacy::RangeFrom<T>) -> Self {
|
||||
Self { start: value.start }
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition;
|
|||
use crate::{ops, range};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, I> ops::Index<I> for [T]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I> const ops::Index<I> for [T]
|
||||
where
|
||||
I: SliceIndex<[T]>,
|
||||
I: ~const SliceIndex<[T]>,
|
||||
{
|
||||
type Output = I::Output;
|
||||
|
||||
|
|
@ -19,9 +20,10 @@ where
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, I> ops::IndexMut<I> for [T]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I> const ops::IndexMut<I> for [T]
|
||||
where
|
||||
I: SliceIndex<[T]>,
|
||||
I: ~const SliceIndex<[T]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn index_mut(&mut self, index: I) -> &mut I::Output {
|
||||
|
|
@ -158,6 +160,8 @@ mod private_slice_index {
|
|||
message = "the type `{T}` cannot be indexed by `{Self}`",
|
||||
label = "slice indices are of type `usize` or ranges of `usize`"
|
||||
)]
|
||||
#[const_trait]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
|
||||
/// The output type returned by methods.
|
||||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||
|
|
@ -208,7 +212,8 @@ pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
|
|||
|
||||
/// The methods `index` and `index_mut` panic if the index is out of bounds.
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for usize {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for usize {
|
||||
type Output = T;
|
||||
|
||||
#[inline]
|
||||
|
|
@ -278,7 +283,8 @@ unsafe impl<T> SliceIndex<[T]> for usize {
|
|||
|
||||
/// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
|
||||
/// than there are for a general `Range<usize>` (which might be `100..3`).
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -354,7 +360,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
|
|||
/// - the start of the range is greater than the end of the range or
|
||||
/// - the end of the range is out of bounds.
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -453,7 +460,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for range::Range<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -491,7 +499,8 @@ unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
|
|||
|
||||
/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -529,7 +538,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
|
|||
|
||||
/// The methods `index` and `index_mut` panic if the start of the range is out of bounds.
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -574,7 +584,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for range::RangeFrom<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -611,7 +622,8 @@ unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
|
|||
}
|
||||
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -650,7 +662,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
|
|||
/// - the start of the range is greater than the end of the range or
|
||||
/// - the end of the range is out of bounds.
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -693,7 +706,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for range::RangeInclusive<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -731,7 +745,8 @@ unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
|
|||
|
||||
/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -568,9 +568,10 @@ impl<T> [T] {
|
|||
#[rustc_no_implicit_autorefs]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn get<I>(&self, index: I) -> Option<&I::Output>
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const fn get<I>(&self, index: I) -> Option<&I::Output>
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
index.get(self)
|
||||
}
|
||||
|
|
@ -594,9 +595,10 @@ impl<T> [T] {
|
|||
#[rustc_no_implicit_autorefs]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
index.get_mut(self)
|
||||
}
|
||||
|
|
@ -633,9 +635,10 @@ impl<T> [T] {
|
|||
#[inline]
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
// SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
|
||||
// the slice is dereferenceable because `self` is a safe reference.
|
||||
|
|
@ -677,9 +680,10 @@ impl<T> [T] {
|
|||
#[inline]
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
// SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
|
||||
// the slice is dereferenceable because `self` is a safe reference.
|
||||
|
|
|
|||
|
|
@ -589,8 +589,9 @@ impl str {
|
|||
/// assert!(v.get(..42).is_none());
|
||||
/// ```
|
||||
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[inline]
|
||||
pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
|
||||
pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
|
||||
i.get(self)
|
||||
}
|
||||
|
||||
|
|
@ -621,8 +622,9 @@ impl str {
|
|||
/// assert_eq!("HEllo", v);
|
||||
/// ```
|
||||
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[inline]
|
||||
pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
|
||||
pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
|
||||
i.get_mut(self)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,9 +49,10 @@ impl PartialOrd for str {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I> ops::Index<I> for str
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<I> const ops::Index<I> for str
|
||||
where
|
||||
I: SliceIndex<str>,
|
||||
I: ~const SliceIndex<str>,
|
||||
{
|
||||
type Output = I::Output;
|
||||
|
||||
|
|
@ -62,9 +63,10 @@ where
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I> ops::IndexMut<I> for str
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<I> const ops::IndexMut<I> for str
|
||||
where
|
||||
I: SliceIndex<str>,
|
||||
I: ~const SliceIndex<str>,
|
||||
{
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: I) -> &mut I::Output {
|
||||
|
|
@ -92,7 +94,8 @@ const fn str_index_overflow_fail() -> ! {
|
|||
///
|
||||
/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
|
||||
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
|
||||
unsafe impl SliceIndex<str> for ops::RangeFull {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeFull {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -156,7 +159,8 @@ unsafe impl SliceIndex<str> for ops::RangeFull {
|
|||
/// // &s[3 .. 100];
|
||||
/// ```
|
||||
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
|
||||
unsafe impl SliceIndex<str> for ops::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::Range<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -260,7 +264,8 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for range::Range<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -431,7 +436,8 @@ unsafe impl SliceIndex<str> for (ops::Bound<usize>, ops::Bound<usize>) {
|
|||
/// Panics if `end` does not point to the starting byte offset of a
|
||||
/// character (as defined by `is_char_boundary`), or if `end > len`.
|
||||
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
|
||||
unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -499,7 +505,8 @@ unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
|
|||
/// Panics if `begin` does not point to the starting byte offset of
|
||||
/// a character (as defined by `is_char_boundary`), or if `begin > len`.
|
||||
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
|
||||
unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -554,7 +561,8 @@ unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for range::RangeFrom<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -625,7 +633,8 @@ unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
|
|||
/// to the ending byte offset of a character (`end + 1` is either a starting
|
||||
/// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -662,7 +671,8 @@ unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -713,7 +723,8 @@ unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
|
|||
/// (`end + 1` is either a starting byte offset as defined by
|
||||
/// `is_char_boundary`, or equal to `len`), or if `end >= len`.
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy
|
||||
#![cfg(target_has_reliable_f128)]
|
||||
|
||||
use core::ops::{Add, Div, Mul, Sub};
|
||||
use std::f128::consts;
|
||||
use std::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
|
|
@ -38,160 +36,9 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa;
|
|||
/// Second pattern over the mantissa
|
||||
const NAN_MASK2: u128 = 0x00005555555555555555555555555555;
|
||||
|
||||
#[test]
|
||||
fn test_num_f128() {
|
||||
// FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128`
|
||||
// function is available on all platforms.
|
||||
let ten = 10f128;
|
||||
let two = 2f128;
|
||||
assert_biteq!(ten.add(two), ten + two);
|
||||
assert_biteq!(ten.sub(two), ten - two);
|
||||
assert_biteq!(ten.mul(two), ten * two);
|
||||
assert_biteq!(ten.div(two), ten / two);
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
assert_biteq!(core::ops::Rem::rem(ten, two), ten % two);
|
||||
}
|
||||
|
||||
// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
|
||||
// the intrinsics.
|
||||
|
||||
#[test]
|
||||
fn test_infinity() {
|
||||
let inf: f128 = f128::INFINITY;
|
||||
assert!(inf.is_infinite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(inf.is_sign_positive());
|
||||
assert!(!inf.is_sign_negative());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_infinity() {
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(!neg_inf.is_sign_positive());
|
||||
assert!(neg_inf.is_sign_negative());
|
||||
assert!(!neg_inf.is_nan());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, neg_inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let zero: f128 = 0.0f128;
|
||||
assert_biteq!(0.0, zero);
|
||||
assert!(!zero.is_infinite());
|
||||
assert!(zero.is_finite());
|
||||
assert!(zero.is_sign_positive());
|
||||
assert!(!zero.is_sign_negative());
|
||||
assert!(!zero.is_nan());
|
||||
assert!(!zero.is_normal());
|
||||
assert_eq!(Fp::Zero, zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_zero() {
|
||||
let neg_zero: f128 = -0.0;
|
||||
assert_eq!(0.0, neg_zero);
|
||||
assert_biteq!(-0.0, neg_zero);
|
||||
assert!(!neg_zero.is_infinite());
|
||||
assert!(neg_zero.is_finite());
|
||||
assert!(!neg_zero.is_sign_positive());
|
||||
assert!(neg_zero.is_sign_negative());
|
||||
assert!(!neg_zero.is_nan());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert_eq!(Fp::Zero, neg_zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one() {
|
||||
let one: f128 = 1.0f128;
|
||||
assert_biteq!(1.0, one);
|
||||
assert!(!one.is_infinite());
|
||||
assert!(one.is_finite());
|
||||
assert!(one.is_sign_positive());
|
||||
assert!(!one.is_sign_negative());
|
||||
assert!(!one.is_nan());
|
||||
assert!(one.is_normal());
|
||||
assert_eq!(Fp::Normal, one.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_nan() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert!(nan.is_nan());
|
||||
assert!(!0.0f128.is_nan());
|
||||
assert!(!5.3f128.is_nan());
|
||||
assert!(!(-10.732f128).is_nan());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!neg_inf.is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_infinite() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert!(!nan.is_infinite());
|
||||
assert!(inf.is_infinite());
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!0.0f128.is_infinite());
|
||||
assert!(!42.8f128.is_infinite());
|
||||
assert!(!(-109.2f128).is_infinite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_finite() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert!(!nan.is_finite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(0.0f128.is_finite());
|
||||
assert!(42.8f128.is_finite());
|
||||
assert!((-109.2f128).is_finite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
let zero: f128 = 0.0f128;
|
||||
let neg_zero: f128 = -0.0;
|
||||
assert!(!nan.is_normal());
|
||||
assert!(!inf.is_normal());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert!(!zero.is_normal());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert!(1f128.is_normal());
|
||||
assert!(1e-4931f128.is_normal());
|
||||
assert!(!1e-4932f128.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
let zero: f128 = 0.0f128;
|
||||
let neg_zero: f128 = -0.0;
|
||||
assert_eq!(nan.classify(), Fp::Nan);
|
||||
assert_eq!(inf.classify(), Fp::Infinite);
|
||||
assert_eq!(neg_inf.classify(), Fp::Infinite);
|
||||
assert_eq!(zero.classify(), Fp::Zero);
|
||||
assert_eq!(neg_zero.classify(), Fp::Zero);
|
||||
assert_eq!(1f128.classify(), Fp::Normal);
|
||||
assert_eq!(1e-4931f128.classify(), Fp::Normal);
|
||||
assert_eq!(1e-4932f128.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f128_math))]
|
||||
fn test_abs() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#![cfg(target_has_reliable_f16)]
|
||||
|
||||
use std::f16::consts;
|
||||
use std::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
|
|
@ -43,151 +42,9 @@ const NAN_MASK1: u16 = 0x02aa;
|
|||
/// Second pattern over the mantissa
|
||||
const NAN_MASK2: u16 = 0x0155;
|
||||
|
||||
#[test]
|
||||
fn test_num_f16() {
|
||||
super::test_num(10f16, 2f16);
|
||||
}
|
||||
|
||||
// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
|
||||
// the intrinsics.
|
||||
|
||||
#[test]
|
||||
fn test_infinity() {
|
||||
let inf: f16 = f16::INFINITY;
|
||||
assert!(inf.is_infinite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(inf.is_sign_positive());
|
||||
assert!(!inf.is_sign_negative());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_infinity() {
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(!neg_inf.is_sign_positive());
|
||||
assert!(neg_inf.is_sign_negative());
|
||||
assert!(!neg_inf.is_nan());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, neg_inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let zero: f16 = 0.0f16;
|
||||
assert_biteq!(0.0, zero);
|
||||
assert!(!zero.is_infinite());
|
||||
assert!(zero.is_finite());
|
||||
assert!(zero.is_sign_positive());
|
||||
assert!(!zero.is_sign_negative());
|
||||
assert!(!zero.is_nan());
|
||||
assert!(!zero.is_normal());
|
||||
assert_eq!(Fp::Zero, zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_zero() {
|
||||
let neg_zero: f16 = -0.0;
|
||||
assert_eq!(0.0, neg_zero);
|
||||
assert_biteq!(-0.0, neg_zero);
|
||||
assert!(!neg_zero.is_infinite());
|
||||
assert!(neg_zero.is_finite());
|
||||
assert!(!neg_zero.is_sign_positive());
|
||||
assert!(neg_zero.is_sign_negative());
|
||||
assert!(!neg_zero.is_nan());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert_eq!(Fp::Zero, neg_zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one() {
|
||||
let one: f16 = 1.0f16;
|
||||
assert_biteq!(1.0, one);
|
||||
assert!(!one.is_infinite());
|
||||
assert!(one.is_finite());
|
||||
assert!(one.is_sign_positive());
|
||||
assert!(!one.is_sign_negative());
|
||||
assert!(!one.is_nan());
|
||||
assert!(one.is_normal());
|
||||
assert_eq!(Fp::Normal, one.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_nan() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert!(nan.is_nan());
|
||||
assert!(!0.0f16.is_nan());
|
||||
assert!(!5.3f16.is_nan());
|
||||
assert!(!(-10.732f16).is_nan());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!neg_inf.is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_infinite() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert!(!nan.is_infinite());
|
||||
assert!(inf.is_infinite());
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!0.0f16.is_infinite());
|
||||
assert!(!42.8f16.is_infinite());
|
||||
assert!(!(-109.2f16).is_infinite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_finite() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert!(!nan.is_finite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(0.0f16.is_finite());
|
||||
assert!(42.8f16.is_finite());
|
||||
assert!((-109.2f16).is_finite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
let zero: f16 = 0.0f16;
|
||||
let neg_zero: f16 = -0.0;
|
||||
assert!(!nan.is_normal());
|
||||
assert!(!inf.is_normal());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert!(!zero.is_normal());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert!(1f16.is_normal());
|
||||
assert!(1e-4f16.is_normal());
|
||||
assert!(!1e-5f16.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
let zero: f16 = 0.0f16;
|
||||
let neg_zero: f16 = -0.0;
|
||||
assert_eq!(nan.classify(), Fp::Nan);
|
||||
assert_eq!(inf.classify(), Fp::Infinite);
|
||||
assert_eq!(neg_inf.classify(), Fp::Infinite);
|
||||
assert_eq!(zero.classify(), Fp::Zero);
|
||||
assert_eq!(neg_zero.classify(), Fp::Zero);
|
||||
assert_eq!(1f16.classify(), Fp::Normal);
|
||||
assert_eq!(1e-4f16.classify(), Fp::Normal);
|
||||
assert_eq!(1e-5f16.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(miri, target_has_reliable_f16_math))]
|
||||
fn test_abs() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use core::f32;
|
||||
use core::f32::consts;
|
||||
use core::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
|
|
@ -30,148 +29,6 @@ const NAN_MASK2: u32 = 0x0055_5555;
|
|||
/// They serve as a way to get an idea of the real precision of floating point operations on different platforms.
|
||||
const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 };
|
||||
|
||||
#[test]
|
||||
fn test_num_f32() {
|
||||
super::test_num(10f32, 2f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_infinity() {
|
||||
let inf: f32 = f32::INFINITY;
|
||||
assert!(inf.is_infinite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(inf.is_sign_positive());
|
||||
assert!(!inf.is_sign_negative());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_infinity() {
|
||||
let neg_inf: f32 = f32::NEG_INFINITY;
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(!neg_inf.is_sign_positive());
|
||||
assert!(neg_inf.is_sign_negative());
|
||||
assert!(!neg_inf.is_nan());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, neg_inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let zero: f32 = 0.0f32;
|
||||
assert_biteq!(0.0, zero);
|
||||
assert!(!zero.is_infinite());
|
||||
assert!(zero.is_finite());
|
||||
assert!(zero.is_sign_positive());
|
||||
assert!(!zero.is_sign_negative());
|
||||
assert!(!zero.is_nan());
|
||||
assert!(!zero.is_normal());
|
||||
assert_eq!(Fp::Zero, zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_zero() {
|
||||
let neg_zero: f32 = -0.0;
|
||||
assert_eq!(0.0, neg_zero);
|
||||
assert_biteq!(-0.0, neg_zero);
|
||||
assert!(!neg_zero.is_infinite());
|
||||
assert!(neg_zero.is_finite());
|
||||
assert!(!neg_zero.is_sign_positive());
|
||||
assert!(neg_zero.is_sign_negative());
|
||||
assert!(!neg_zero.is_nan());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert_eq!(Fp::Zero, neg_zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one() {
|
||||
let one: f32 = 1.0f32;
|
||||
assert_biteq!(1.0, one);
|
||||
assert!(!one.is_infinite());
|
||||
assert!(one.is_finite());
|
||||
assert!(one.is_sign_positive());
|
||||
assert!(!one.is_sign_negative());
|
||||
assert!(!one.is_nan());
|
||||
assert!(one.is_normal());
|
||||
assert_eq!(Fp::Normal, one.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_nan() {
|
||||
let nan: f32 = f32::NAN;
|
||||
let inf: f32 = f32::INFINITY;
|
||||
let neg_inf: f32 = f32::NEG_INFINITY;
|
||||
assert!(nan.is_nan());
|
||||
assert!(!0.0f32.is_nan());
|
||||
assert!(!5.3f32.is_nan());
|
||||
assert!(!(-10.732f32).is_nan());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!neg_inf.is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_infinite() {
|
||||
let nan: f32 = f32::NAN;
|
||||
let inf: f32 = f32::INFINITY;
|
||||
let neg_inf: f32 = f32::NEG_INFINITY;
|
||||
assert!(!nan.is_infinite());
|
||||
assert!(inf.is_infinite());
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!0.0f32.is_infinite());
|
||||
assert!(!42.8f32.is_infinite());
|
||||
assert!(!(-109.2f32).is_infinite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_finite() {
|
||||
let nan: f32 = f32::NAN;
|
||||
let inf: f32 = f32::INFINITY;
|
||||
let neg_inf: f32 = f32::NEG_INFINITY;
|
||||
assert!(!nan.is_finite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(0.0f32.is_finite());
|
||||
assert!(42.8f32.is_finite());
|
||||
assert!((-109.2f32).is_finite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
let nan: f32 = f32::NAN;
|
||||
let inf: f32 = f32::INFINITY;
|
||||
let neg_inf: f32 = f32::NEG_INFINITY;
|
||||
let zero: f32 = 0.0f32;
|
||||
let neg_zero: f32 = -0.0;
|
||||
assert!(!nan.is_normal());
|
||||
assert!(!inf.is_normal());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert!(!zero.is_normal());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert!(1f32.is_normal());
|
||||
assert!(1e-37f32.is_normal());
|
||||
assert!(!1e-38f32.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
let nan: f32 = f32::NAN;
|
||||
let inf: f32 = f32::INFINITY;
|
||||
let neg_inf: f32 = f32::NEG_INFINITY;
|
||||
let zero: f32 = 0.0f32;
|
||||
let neg_zero: f32 = -0.0;
|
||||
assert_eq!(nan.classify(), Fp::Nan);
|
||||
assert_eq!(inf.classify(), Fp::Infinite);
|
||||
assert_eq!(neg_inf.classify(), Fp::Infinite);
|
||||
assert_eq!(zero.classify(), Fp::Zero);
|
||||
assert_eq!(neg_zero.classify(), Fp::Zero);
|
||||
assert_eq!(1f32.classify(), Fp::Normal);
|
||||
assert_eq!(1e-37f32.classify(), Fp::Normal);
|
||||
assert_eq!(1e-38f32.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs() {
|
||||
assert_biteq!(f32::INFINITY.abs(), f32::INFINITY);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use core::f64;
|
||||
use core::f64::consts;
|
||||
use core::num::FpCategory as Fp;
|
||||
|
||||
use super::{assert_approx_eq, assert_biteq};
|
||||
|
||||
|
|
@ -25,147 +24,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa;
|
|||
/// Second pattern over the mantissa
|
||||
const NAN_MASK2: u64 = 0x0005_5555_5555_5555;
|
||||
|
||||
#[test]
|
||||
fn test_num_f64() {
|
||||
super::test_num(10f64, 2f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_infinity() {
|
||||
let inf: f64 = f64::INFINITY;
|
||||
assert!(inf.is_infinite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(inf.is_sign_positive());
|
||||
assert!(!inf.is_sign_negative());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_infinity() {
|
||||
let neg_inf: f64 = f64::NEG_INFINITY;
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(!neg_inf.is_sign_positive());
|
||||
assert!(neg_inf.is_sign_negative());
|
||||
assert!(!neg_inf.is_nan());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert_eq!(Fp::Infinite, neg_inf.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let zero: f64 = 0.0f64;
|
||||
assert_biteq!(0.0, zero);
|
||||
assert!(!zero.is_infinite());
|
||||
assert!(zero.is_finite());
|
||||
assert!(zero.is_sign_positive());
|
||||
assert!(!zero.is_sign_negative());
|
||||
assert!(!zero.is_nan());
|
||||
assert!(!zero.is_normal());
|
||||
assert_eq!(Fp::Zero, zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_zero() {
|
||||
let neg_zero: f64 = -0.0;
|
||||
assert_eq!(0.0, neg_zero);
|
||||
assert_biteq!(-0.0, neg_zero);
|
||||
assert!(!neg_zero.is_infinite());
|
||||
assert!(neg_zero.is_finite());
|
||||
assert!(!neg_zero.is_sign_positive());
|
||||
assert!(neg_zero.is_sign_negative());
|
||||
assert!(!neg_zero.is_nan());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert_eq!(Fp::Zero, neg_zero.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one() {
|
||||
let one: f64 = 1.0f64;
|
||||
assert_biteq!(1.0, one);
|
||||
assert!(!one.is_infinite());
|
||||
assert!(one.is_finite());
|
||||
assert!(one.is_sign_positive());
|
||||
assert!(!one.is_sign_negative());
|
||||
assert!(!one.is_nan());
|
||||
assert!(one.is_normal());
|
||||
assert_eq!(Fp::Normal, one.classify());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_nan() {
|
||||
let nan: f64 = f64::NAN;
|
||||
let inf: f64 = f64::INFINITY;
|
||||
let neg_inf: f64 = f64::NEG_INFINITY;
|
||||
assert!(nan.is_nan());
|
||||
assert!(!0.0f64.is_nan());
|
||||
assert!(!5.3f64.is_nan());
|
||||
assert!(!(-10.732f64).is_nan());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!neg_inf.is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_infinite() {
|
||||
let nan: f64 = f64::NAN;
|
||||
let inf: f64 = f64::INFINITY;
|
||||
let neg_inf: f64 = f64::NEG_INFINITY;
|
||||
assert!(!nan.is_infinite());
|
||||
assert!(inf.is_infinite());
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!0.0f64.is_infinite());
|
||||
assert!(!42.8f64.is_infinite());
|
||||
assert!(!(-109.2f64).is_infinite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_finite() {
|
||||
let nan: f64 = f64::NAN;
|
||||
let inf: f64 = f64::INFINITY;
|
||||
let neg_inf: f64 = f64::NEG_INFINITY;
|
||||
assert!(!nan.is_finite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(0.0f64.is_finite());
|
||||
assert!(42.8f64.is_finite());
|
||||
assert!((-109.2f64).is_finite());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
let nan: f64 = f64::NAN;
|
||||
let inf: f64 = f64::INFINITY;
|
||||
let neg_inf: f64 = f64::NEG_INFINITY;
|
||||
let zero: f64 = 0.0f64;
|
||||
let neg_zero: f64 = -0.0;
|
||||
assert!(!nan.is_normal());
|
||||
assert!(!inf.is_normal());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert!(!zero.is_normal());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert!(1f64.is_normal());
|
||||
assert!(1e-307f64.is_normal());
|
||||
assert!(!1e-308f64.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
let nan: f64 = f64::NAN;
|
||||
let inf: f64 = f64::INFINITY;
|
||||
let neg_inf: f64 = f64::NEG_INFINITY;
|
||||
let zero: f64 = 0.0f64;
|
||||
let neg_zero: f64 = -0.0;
|
||||
assert_eq!(nan.classify(), Fp::Nan);
|
||||
assert_eq!(inf.classify(), Fp::Infinite);
|
||||
assert_eq!(neg_inf.classify(), Fp::Infinite);
|
||||
assert_eq!(zero.classify(), Fp::Zero);
|
||||
assert_eq!(neg_zero.classify(), Fp::Zero);
|
||||
assert_eq!(1e-307f64.classify(), Fp::Normal);
|
||||
assert_eq!(1e-308f64.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs() {
|
||||
assert_biteq!(f64::INFINITY.abs(), f64::INFINITY);
|
||||
|
|
|
|||
|
|
@ -1,28 +1,40 @@
|
|||
use std::fmt;
|
||||
use std::num::FpCategory as Fp;
|
||||
use std::ops::{Add, Div, Mul, Rem, Sub};
|
||||
|
||||
/// Set the default tolerance for float comparison based on the type.
|
||||
trait Approx {
|
||||
const LIM: Self;
|
||||
trait TestableFloat {
|
||||
/// Set the default tolerance for float comparison based on the type.
|
||||
const APPROX: Self;
|
||||
const MIN_POSITIVE_NORMAL: Self;
|
||||
const MAX_SUBNORMAL: Self;
|
||||
}
|
||||
|
||||
impl Approx for f16 {
|
||||
const LIM: Self = 1e-3;
|
||||
impl TestableFloat for f16 {
|
||||
const APPROX: Self = 1e-3;
|
||||
const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
|
||||
const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
|
||||
}
|
||||
impl Approx for f32 {
|
||||
const LIM: Self = 1e-6;
|
||||
|
||||
impl TestableFloat for f32 {
|
||||
const APPROX: Self = 1e-6;
|
||||
const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
|
||||
const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
|
||||
}
|
||||
impl Approx for f64 {
|
||||
const LIM: Self = 1e-6;
|
||||
|
||||
impl TestableFloat for f64 {
|
||||
const APPROX: Self = 1e-6;
|
||||
const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
|
||||
const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
|
||||
}
|
||||
impl Approx for f128 {
|
||||
const LIM: Self = 1e-9;
|
||||
|
||||
impl TestableFloat for f128 {
|
||||
const APPROX: Self = 1e-9;
|
||||
const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE;
|
||||
const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down();
|
||||
}
|
||||
|
||||
/// Determine the tolerance for values of the argument type.
|
||||
const fn lim_for_ty<T: Approx + Copy>(_x: T) -> T {
|
||||
T::LIM
|
||||
const fn lim_for_ty<T: TestableFloat + Copy>(_x: T) -> T {
|
||||
T::APPROX
|
||||
}
|
||||
|
||||
// We have runtime ("rt") and const versions of these macros.
|
||||
|
|
@ -187,9 +199,11 @@ macro_rules! float_test {
|
|||
$( $( #[$const_meta] )+ )?
|
||||
mod const_ {
|
||||
#[allow(unused)]
|
||||
use super::Approx;
|
||||
use super::TestableFloat;
|
||||
#[allow(unused)]
|
||||
use std::num::FpCategory as Fp;
|
||||
#[allow(unused)]
|
||||
use std::ops::{Add, Div, Mul, Rem, Sub};
|
||||
// Shadow the runtime versions of the macro with const-compatible versions.
|
||||
#[allow(unused)]
|
||||
use $crate::floats::{
|
||||
|
|
@ -229,30 +243,42 @@ macro_rules! float_test {
|
|||
};
|
||||
}
|
||||
|
||||
/// Helper function for testing numeric operations
|
||||
pub fn test_num<T>(ten: T, two: T)
|
||||
where
|
||||
T: PartialEq
|
||||
+ Add<Output = T>
|
||||
+ Sub<Output = T>
|
||||
+ Mul<Output = T>
|
||||
+ Div<Output = T>
|
||||
+ Rem<Output = T>
|
||||
+ fmt::Debug
|
||||
+ Copy,
|
||||
{
|
||||
assert_eq!(ten.add(two), ten + two);
|
||||
assert_eq!(ten.sub(two), ten - two);
|
||||
assert_eq!(ten.mul(two), ten * two);
|
||||
assert_eq!(ten.div(two), ten / two);
|
||||
assert_eq!(ten.rem(two), ten % two);
|
||||
}
|
||||
|
||||
mod f128;
|
||||
mod f16;
|
||||
mod f32;
|
||||
mod f64;
|
||||
|
||||
float_test! {
|
||||
name: num,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let two: Float = 2.0;
|
||||
let ten: Float = 10.0;
|
||||
assert_biteq!(ten.add(two), ten + two);
|
||||
assert_biteq!(ten.sub(two), ten - two);
|
||||
assert_biteq!(ten.mul(two), ten * two);
|
||||
assert_biteq!(ten.div(two), ten / two);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on
|
||||
// all platforms.
|
||||
float_test! {
|
||||
name: num_rem,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16_math))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
|
||||
},
|
||||
test<Float> {
|
||||
let two: Float = 2.0;
|
||||
let ten: Float = 10.0;
|
||||
assert_biteq!(ten.rem(two), ten % two);
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: nan,
|
||||
attrs: {
|
||||
|
|
@ -273,6 +299,213 @@ float_test! {
|
|||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: infinity,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let inf: Float = Float::INFINITY;
|
||||
assert!(inf.is_infinite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(inf.is_sign_positive());
|
||||
assert!(!inf.is_sign_negative());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!inf.is_normal());
|
||||
assert!(matches!(inf.classify(), Fp::Infinite));
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: neg_infinity,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let neg_inf: Float = Float::NEG_INFINITY;
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(!neg_inf.is_sign_positive());
|
||||
assert!(neg_inf.is_sign_negative());
|
||||
assert!(!neg_inf.is_nan());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert!(matches!(neg_inf.classify(), Fp::Infinite));
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: zero,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let zero: Float = 0.0;
|
||||
assert_biteq!(0.0, zero);
|
||||
assert!(!zero.is_infinite());
|
||||
assert!(zero.is_finite());
|
||||
assert!(zero.is_sign_positive());
|
||||
assert!(!zero.is_sign_negative());
|
||||
assert!(!zero.is_nan());
|
||||
assert!(!zero.is_normal());
|
||||
assert!(matches!(zero.classify(), Fp::Zero));
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: neg_zero,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let neg_zero: Float = -0.0;
|
||||
assert!(0.0 == neg_zero);
|
||||
assert_biteq!(-0.0, neg_zero);
|
||||
assert!(!neg_zero.is_infinite());
|
||||
assert!(neg_zero.is_finite());
|
||||
assert!(!neg_zero.is_sign_positive());
|
||||
assert!(neg_zero.is_sign_negative());
|
||||
assert!(!neg_zero.is_nan());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert!(matches!(neg_zero.classify(), Fp::Zero));
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: one,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let one: Float = 1.0;
|
||||
assert_biteq!(1.0, one);
|
||||
assert!(!one.is_infinite());
|
||||
assert!(one.is_finite());
|
||||
assert!(one.is_sign_positive());
|
||||
assert!(!one.is_sign_negative());
|
||||
assert!(!one.is_nan());
|
||||
assert!(one.is_normal());
|
||||
assert!(matches!(one.classify(), Fp::Normal));
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: is_nan,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let nan: Float = Float::NAN;
|
||||
let inf: Float = Float::INFINITY;
|
||||
let neg_inf: Float = Float::NEG_INFINITY;
|
||||
let zero: Float = 0.0;
|
||||
let pos: Float = 5.3;
|
||||
let neg: Float = -10.732;
|
||||
assert!(nan.is_nan());
|
||||
assert!(!zero.is_nan());
|
||||
assert!(!pos.is_nan());
|
||||
assert!(!neg.is_nan());
|
||||
assert!(!inf.is_nan());
|
||||
assert!(!neg_inf.is_nan());
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: is_infinite,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let nan: Float = Float::NAN;
|
||||
let inf: Float = Float::INFINITY;
|
||||
let neg_inf: Float = Float::NEG_INFINITY;
|
||||
let zero: Float = 0.0;
|
||||
let pos: Float = 42.8;
|
||||
let neg: Float = -109.2;
|
||||
assert!(!nan.is_infinite());
|
||||
assert!(inf.is_infinite());
|
||||
assert!(neg_inf.is_infinite());
|
||||
assert!(!zero.is_infinite());
|
||||
assert!(!pos.is_infinite());
|
||||
assert!(!neg.is_infinite());
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: is_finite,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let nan: Float = Float::NAN;
|
||||
let inf: Float = Float::INFINITY;
|
||||
let neg_inf: Float = Float::NEG_INFINITY;
|
||||
let zero: Float = 0.0;
|
||||
let pos: Float = 42.8;
|
||||
let neg: Float = -109.2;
|
||||
assert!(!nan.is_finite());
|
||||
assert!(!inf.is_finite());
|
||||
assert!(!neg_inf.is_finite());
|
||||
assert!(zero.is_finite());
|
||||
assert!(pos.is_finite());
|
||||
assert!(neg.is_finite());
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: is_normal,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
let nan: Float = Float::NAN;
|
||||
let inf: Float = Float::INFINITY;
|
||||
let neg_inf: Float = Float::NEG_INFINITY;
|
||||
let zero: Float = 0.0;
|
||||
let neg_zero: Float = -0.0;
|
||||
let one : Float = 1.0;
|
||||
assert!(!nan.is_normal());
|
||||
assert!(!inf.is_normal());
|
||||
assert!(!neg_inf.is_normal());
|
||||
assert!(!zero.is_normal());
|
||||
assert!(!neg_zero.is_normal());
|
||||
assert!(one.is_normal());
|
||||
assert!(Float::MIN_POSITIVE_NORMAL.is_normal());
|
||||
assert!(!Float::MAX_SUBNORMAL.is_normal());
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: classify,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
},
|
||||
test<Float> {
|
||||
let nan: Float = Float::NAN;
|
||||
let inf: Float = Float::INFINITY;
|
||||
let neg_inf: Float = Float::NEG_INFINITY;
|
||||
let zero: Float = 0.0;
|
||||
let neg_zero: Float = -0.0;
|
||||
let one: Float = 1.0;
|
||||
assert!(matches!(nan.classify(), Fp::Nan));
|
||||
assert!(matches!(inf.classify(), Fp::Infinite));
|
||||
assert!(matches!(neg_inf.classify(), Fp::Infinite));
|
||||
assert!(matches!(zero.classify(), Fp::Zero));
|
||||
assert!(matches!(neg_zero.classify(), Fp::Zero));
|
||||
assert!(matches!(one.classify(), Fp::Normal));
|
||||
assert!(matches!(Float::MIN_POSITIVE_NORMAL.classify(), Fp::Normal));
|
||||
assert!(matches!(Float::MAX_SUBNORMAL.classify(), Fp::Subnormal));
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: min,
|
||||
attrs: {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#![feature(const_destruct)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(const_float_round_methods)]
|
||||
#![feature(const_ops)]
|
||||
#![feature(const_ref_cell)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(core_float_math)]
|
||||
|
|
|
|||
|
|
@ -469,6 +469,29 @@ impl<T: 'static> LocalKey<Cell<T>> {
|
|||
pub fn replace(&'static self, value: T) -> T {
|
||||
self.with(|cell| cell.replace(value))
|
||||
}
|
||||
|
||||
/// Updates the contained value using a function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(local_key_cell_update)]
|
||||
/// use std::cell::Cell;
|
||||
///
|
||||
/// thread_local! {
|
||||
/// static X: Cell<i32> = const { Cell::new(5) };
|
||||
/// }
|
||||
///
|
||||
/// X.update(|x| x + 1);
|
||||
/// assert_eq!(X.get(), 6);
|
||||
/// ```
|
||||
#[unstable(feature = "local_key_cell_update", issue = "143989")]
|
||||
pub fn update(&'static self, f: impl FnOnce(T) -> T)
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
self.with(|cell| cell.update(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> LocalKey<RefCell<T>> {
|
||||
|
|
|
|||
|
|
@ -32,10 +32,11 @@ are built for NetBSD 8.x but also work on newer OS versions).
|
|||
## Target Maintainers
|
||||
|
||||
[@he32](https://github.com/he32)
|
||||
[@0323pin](https://github.com/0323pin)
|
||||
|
||||
Further contacts:
|
||||
|
||||
- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust
|
||||
- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust188/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust. Note that we have the convention of having multiple rust versions active in pkgsrc-wip at any one time, so the version number is part of the directory name, and from time to time old versions are culled so this is not a fully "stable" link.
|
||||
- [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc.
|
||||
- [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself
|
||||
|
||||
|
|
|
|||
|
|
@ -759,79 +759,48 @@ impl Item {
|
|||
Some(tcx.visibility(def_id))
|
||||
}
|
||||
|
||||
fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
|
||||
const ALLOWED_ATTRIBUTES: &[Symbol] =
|
||||
&[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
|
||||
/// Get a list of attributes excluding `#[repr]` to display.
|
||||
///
|
||||
/// Only used by the HTML output-format.
|
||||
fn attributes_without_repr(&self) -> Vec<String> {
|
||||
self.attrs
|
||||
.other_attrs
|
||||
.iter()
|
||||
.filter_map(|attr| {
|
||||
if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr {
|
||||
.filter_map(|attr| match attr {
|
||||
hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
|
||||
Some(format!("#[link_section = \"{name}\"]"))
|
||||
}
|
||||
// NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
|
||||
// It is also used by cargo-semver-checks.
|
||||
else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
|
||||
hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
|
||||
Some("#[no_mangle]".to_string())
|
||||
} else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
|
||||
{
|
||||
Some(format!("#[export_name = \"{name}\"]"))
|
||||
} else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr {
|
||||
Some("#[non_exhaustive]".to_string())
|
||||
} else if is_json {
|
||||
match attr {
|
||||
// rustdoc-json stores this in `Item::deprecation`, so we
|
||||
// don't want it it `Item::attrs`.
|
||||
hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None,
|
||||
// We have separate pretty-printing logic for `#[repr(..)]` attributes.
|
||||
hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None,
|
||||
// target_feature is special-cased because cargo-semver-checks uses it
|
||||
hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => {
|
||||
let mut output = String::new();
|
||||
for (i, (feature, _)) in features.iter().enumerate() {
|
||||
if i != 0 {
|
||||
output.push_str(", ");
|
||||
}
|
||||
output.push_str(&format!("enable=\"{}\"", feature.as_str()));
|
||||
}
|
||||
Some(format!("#[target_feature({output})]"))
|
||||
}
|
||||
hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => {
|
||||
Some("#[automatically_derived]".to_string())
|
||||
}
|
||||
_ => Some({
|
||||
let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
|
||||
assert_eq!(s.pop(), Some('\n'));
|
||||
s
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
if !attr.has_any_name(ALLOWED_ATTRIBUTES) {
|
||||
return None;
|
||||
}
|
||||
Some(
|
||||
rustc_hir_pretty::attribute_to_string(&tcx, attr)
|
||||
.replace("\\\n", "")
|
||||
.replace('\n', "")
|
||||
.replace(" ", " "),
|
||||
)
|
||||
}
|
||||
hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
|
||||
Some(format!("#[export_name = \"{name}\"]"))
|
||||
}
|
||||
hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
|
||||
Some("#[non_exhaustive]".to_string())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
|
||||
let mut attrs = self.attributes_without_repr(tcx, is_json);
|
||||
/// Get a list of attributes to display on this item.
|
||||
///
|
||||
/// Only used by the HTML output-format.
|
||||
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
|
||||
let mut attrs = self.attributes_without_repr();
|
||||
|
||||
if let Some(repr_attr) = self.repr(tcx, cache, is_json) {
|
||||
if let Some(repr_attr) = self.repr(tcx, cache) {
|
||||
attrs.push(repr_attr);
|
||||
}
|
||||
attrs
|
||||
}
|
||||
|
||||
/// Returns a stringified `#[repr(...)]` attribute.
|
||||
pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
|
||||
repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
|
||||
///
|
||||
/// Only used by the HTML output-format.
|
||||
pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
|
||||
repr_attributes(tcx, cache, self.def_id()?, self.type_())
|
||||
}
|
||||
|
||||
pub fn is_doc_hidden(&self) -> bool {
|
||||
|
|
@ -843,12 +812,14 @@ impl Item {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return a string representing the `#[repr]` attribute if present.
|
||||
///
|
||||
/// Only used by the HTML output-format.
|
||||
pub(crate) fn repr_attributes(
|
||||
tcx: TyCtxt<'_>,
|
||||
cache: &Cache,
|
||||
def_id: DefId,
|
||||
item_type: ItemType,
|
||||
is_json: bool,
|
||||
) -> Option<String> {
|
||||
use rustc_abi::IntegerType;
|
||||
|
||||
|
|
@ -865,7 +836,6 @@ pub(crate) fn repr_attributes(
|
|||
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
|
||||
// field is public in case all fields are 1-ZST fields.
|
||||
let render_transparent = cache.document_private
|
||||
|| is_json
|
||||
|| adt
|
||||
.all_fields()
|
||||
.find(|field| {
|
||||
|
|
|
|||
|
|
@ -1191,7 +1191,7 @@ fn render_assoc_item(
|
|||
// a whitespace prefix and newline.
|
||||
fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| {
|
||||
for a in it.attributes(cx.tcx(), cx.cache(), false) {
|
||||
for a in it.attributes(cx.tcx(), cx.cache()) {
|
||||
writeln!(f, "{prefix}{a}")?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -1207,7 +1207,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) {
|
|||
// When an attribute is rendered inside a <code> tag, it is formatted using
|
||||
// a div to produce a newline after it.
|
||||
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
|
||||
for attr in it.attributes(cx.tcx(), cx.cache(), false) {
|
||||
for attr in it.attributes(cx.tcx(), cx.cache()) {
|
||||
render_code_attribute(CodeAttribute(attr), w);
|
||||
}
|
||||
}
|
||||
|
|
@ -1219,7 +1219,7 @@ fn render_repr_attributes_in_code(
|
|||
def_id: DefId,
|
||||
item_type: ItemType,
|
||||
) {
|
||||
if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) {
|
||||
if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
|
||||
render_code_attribute(CodeAttribute(repr), w);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1487,12 +1487,11 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
|
|||
self.cx.cache(),
|
||||
self.def_id,
|
||||
ItemType::Union,
|
||||
false,
|
||||
) {
|
||||
writeln!(f, "{repr}")?;
|
||||
};
|
||||
} else {
|
||||
for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) {
|
||||
for a in self.it.attributes(self.cx.tcx(), self.cx.cache()) {
|
||||
writeln!(f, "{a}")?;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@
|
|||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::ast;
|
||||
use rustc_attr_data_structures::{self as attrs, DeprecatedSince};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{HeaderSafety, Safety};
|
||||
use rustc_metadata::rendered_const;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::{Pos, kw, sym};
|
||||
use rustdoc_json_types::*;
|
||||
|
|
@ -39,7 +41,12 @@ impl JsonRenderer<'_> {
|
|||
})
|
||||
.collect();
|
||||
let docs = item.opt_doc_value();
|
||||
let attrs = item.attributes(self.tcx, &self.cache, true);
|
||||
let attrs = item
|
||||
.attrs
|
||||
.other_attrs
|
||||
.iter()
|
||||
.filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx))
|
||||
.collect();
|
||||
let span = item.span(self.tcx);
|
||||
let visibility = item.visibility(self.tcx);
|
||||
let clean::ItemInner { name, item_id, .. } = *item.inner;
|
||||
|
|
@ -886,3 +893,93 @@ impl FromClean<ItemType> for ItemKind {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Maybe convert a attribute from hir to json.
|
||||
///
|
||||
/// Returns `None` if the attribute shouldn't be in the output.
|
||||
fn maybe_from_hir_attr(
|
||||
attr: &hir::Attribute,
|
||||
item_id: ItemId,
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> Option<Attribute> {
|
||||
use attrs::AttributeKind as AK;
|
||||
|
||||
let kind = match attr {
|
||||
hir::Attribute::Parsed(kind) => kind,
|
||||
|
||||
hir::Attribute::Unparsed(_) => {
|
||||
// FIXME: We should handle `#[doc(hidden)]`.
|
||||
return Some(other_attr(tcx, attr));
|
||||
}
|
||||
};
|
||||
|
||||
Some(match kind {
|
||||
AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation.
|
||||
AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"),
|
||||
|
||||
AK::MustUse { reason, span: _ } => {
|
||||
Attribute::MustUse { reason: reason.map(|s| s.to_string()) }
|
||||
}
|
||||
AK::Repr { .. } => repr_attr(
|
||||
tcx,
|
||||
item_id.as_def_id().expect("all items that could have #[repr] have a DefId"),
|
||||
),
|
||||
AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()),
|
||||
AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()),
|
||||
AK::TargetFeature(features, _span) => Attribute::TargetFeature {
|
||||
enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(),
|
||||
},
|
||||
|
||||
AK::NoMangle(_) => Attribute::NoMangle,
|
||||
AK::NonExhaustive(_) => Attribute::NonExhaustive,
|
||||
AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived,
|
||||
|
||||
_ => other_attr(tcx, attr),
|
||||
})
|
||||
}
|
||||
|
||||
fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute {
|
||||
let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
|
||||
assert_eq!(s.pop(), Some('\n'));
|
||||
Attribute::Other(s)
|
||||
}
|
||||
|
||||
fn repr_attr(tcx: TyCtxt<'_>, def_id: DefId) -> Attribute {
|
||||
let repr = tcx.adt_def(def_id).repr();
|
||||
|
||||
let kind = if repr.c() {
|
||||
ReprKind::C
|
||||
} else if repr.transparent() {
|
||||
ReprKind::Transparent
|
||||
} else if repr.simd() {
|
||||
ReprKind::Simd
|
||||
} else {
|
||||
ReprKind::Rust
|
||||
};
|
||||
|
||||
let align = repr.align.map(|a| a.bytes());
|
||||
let packed = repr.pack.map(|p| p.bytes());
|
||||
let int = repr.int.map(format_integer_type);
|
||||
|
||||
Attribute::Repr(AttributeRepr { kind, align, packed, int })
|
||||
}
|
||||
|
||||
fn format_integer_type(it: rustc_abi::IntegerType) -> String {
|
||||
use rustc_abi::Integer::*;
|
||||
use rustc_abi::IntegerType::*;
|
||||
match it {
|
||||
Pointer(true) => "isize",
|
||||
Pointer(false) => "usize",
|
||||
Fixed(I8, true) => "i8",
|
||||
Fixed(I8, false) => "u8",
|
||||
Fixed(I16, true) => "i16",
|
||||
Fixed(I16, false) => "u16",
|
||||
Fixed(I32, true) => "i32",
|
||||
Fixed(I32, false) => "u32",
|
||||
Fixed(I64, true) => "i64",
|
||||
Fixed(I64, false) => "u64",
|
||||
Fixed(I128, true) => "i128",
|
||||
Fixed(I128, false) => "u128",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
|
|||
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
|
||||
// are deliberately not in a doc comment, because they need not be in public docs.)
|
||||
//
|
||||
// Latest feature: Pretty printing of no_mangle attributes changed
|
||||
pub const FORMAT_VERSION: u32 = 53;
|
||||
// Latest feature: Structured Attributes
|
||||
pub const FORMAT_VERSION: u32 = 54;
|
||||
|
||||
/// The root of the emitted JSON blob.
|
||||
///
|
||||
|
|
@ -195,13 +195,94 @@ pub struct Item {
|
|||
/// - `#[repr(C)]` and other reprs also appear as themselves,
|
||||
/// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`.
|
||||
/// Multiple repr attributes on the same item may be combined into an equivalent single attr.
|
||||
pub attrs: Vec<String>,
|
||||
pub attrs: Vec<Attribute>,
|
||||
/// Information about the item’s deprecation, if present.
|
||||
pub deprecation: Option<Deprecation>,
|
||||
/// The type-specific fields describing this item.
|
||||
pub inner: ItemEnum,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
/// An attribute, e.g. `#[repr(C)]`
|
||||
///
|
||||
/// This doesn't include:
|
||||
/// - `#[doc = "Doc Comment"]` or `/// Doc comment`. These are in [`Item::docs`] instead.
|
||||
/// - `#[deprecated]`. These are in [`Item::deprecation`] instead.
|
||||
pub enum Attribute {
|
||||
/// `#[non_exhaustive]`
|
||||
NonExhaustive,
|
||||
|
||||
/// `#[must_use]`
|
||||
MustUse { reason: Option<String> },
|
||||
|
||||
/// `#[export_name = "name"]`
|
||||
ExportName(String),
|
||||
|
||||
/// `#[link_section = "name"]`
|
||||
LinkSection(String),
|
||||
|
||||
/// `#[automatically_derived]`
|
||||
AutomaticallyDerived,
|
||||
|
||||
/// `#[repr]`
|
||||
Repr(AttributeRepr),
|
||||
|
||||
/// `#[no_mangle]`
|
||||
NoMangle,
|
||||
|
||||
/// #[target_feature(enable = "feature1", enable = "feature2")]
|
||||
TargetFeature { enable: Vec<String> },
|
||||
|
||||
/// Something else.
|
||||
///
|
||||
/// Things here are explicitly *not* covered by the [`FORMAT_VERSION`]
|
||||
/// constant, and may change without bumping the format version.
|
||||
///
|
||||
/// As an implementation detail, this is currently either:
|
||||
/// 1. A HIR debug printing, like `"#[attr = Optimize(Speed)]"`
|
||||
/// 2. The attribute as it appears in source form, like
|
||||
/// `"#[optimize(speed)]"`.
|
||||
Other(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
/// The contents of a `#[repr(...)]` attribute.
|
||||
///
|
||||
/// Used in [`Attribute::Repr`].
|
||||
pub struct AttributeRepr {
|
||||
/// The representation, e.g. `#[repr(C)]`, `#[repr(transparent)]`
|
||||
pub kind: ReprKind,
|
||||
|
||||
/// Alignment in bytes, if explicitly specified by `#[repr(align(...)]`.
|
||||
pub align: Option<u64>,
|
||||
/// Alignment in bytes, if explicitly specified by `#[repr(packed(...)]]`.
|
||||
pub packed: Option<u64>,
|
||||
|
||||
/// The integer type for an enum descriminant, if explicitly specified.
|
||||
///
|
||||
/// e.g. `"i32"`, for `#[repr(C, i32)]`
|
||||
pub int: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
/// The kind of `#[repr]`.
|
||||
///
|
||||
/// See [AttributeRepr::kind]`.
|
||||
pub enum ReprKind {
|
||||
/// `#[repr(Rust)]`
|
||||
///
|
||||
/// Also the default.
|
||||
Rust,
|
||||
/// `#[repr(C)]`
|
||||
C,
|
||||
/// `#[repr(transparent)]
|
||||
Transparent,
|
||||
/// `#[repr(simd)]`
|
||||
Simd,
|
||||
}
|
||||
|
||||
/// A range of source code.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Span {
|
||||
|
|
@ -1343,7 +1424,7 @@ pub struct Static {
|
|||
|
||||
/// Is the static `unsafe`?
|
||||
///
|
||||
/// This is only true if it's in an `extern` block, and not explicity marked
|
||||
/// This is only true if it's in an `extern` block, and not explicitly marked
|
||||
/// as `safe`.
|
||||
///
|
||||
/// ```rust
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_index::IndexVec;
|
|||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols::ExportedSymbol;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout};
|
||||
use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
let v: Vec<u16> = vec![1, 2];
|
||||
// This read is also misaligned. We make sure that the OOB message has priority.
|
||||
let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; //~ ERROR: before the beginning of the allocation
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC-0x5 which points to before the beginning of the allocation
|
||||
--> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC
|
||||
|
|
||||
LL | let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
help: ALLOC was allocated here:
|
||||
--> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC
|
||||
|
|
||||
LL | let v: Vec<u16> = vec![1, 2];
|
||||
| ^^^^^^^^^^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC
|
||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
let v = [0i8; 4];
|
||||
let x = &v as *const i8;
|
||||
let x = unsafe { x.wrapping_offset(-1).offset(-1) }; //~ERROR: before the beginning of the allocation
|
||||
panic!("this should never print: {:?}", x);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC-0x1 which points to before the beginning of the allocation
|
||||
--> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC
|
||||
|
|
||||
LL | let x = unsafe { x.wrapping_offset(-1).offset(-1) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
help: ALLOC was allocated here:
|
||||
--> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC
|
||||
|
|
||||
LL | let v = [0i8; 4];
|
||||
| ^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -335,7 +335,9 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec<String>) {
|
|||
std::process::exit(code);
|
||||
} else {
|
||||
println!("died due to signal {}", code);
|
||||
std::process::exit(3);
|
||||
// Behave like bash and other tools and exit with 128 + the signal
|
||||
// number. That way we can avoid special case code in other places.
|
||||
std::process::exit(128 + code);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -885,9 +885,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.4.51"
|
||||
version = "0.4.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328"
|
||||
checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3"
|
|||
mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
|
||||
|
||||
[dependencies.mdbook]
|
||||
version = "0.4.51"
|
||||
version = "0.4.52"
|
||||
default-features = false
|
||||
features = ["search"]
|
||||
|
|
|
|||
40
src/tools/tidy/src/filenames.rs
Normal file
40
src/tools/tidy/src/filenames.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//! Tidy check to ensure that there are no filenames containing forbidden characters
|
||||
//! checked into the source tree by accident:
|
||||
//! - Non-UTF8 filenames
|
||||
//! - Control characters such as CR or TAB
|
||||
//! - Filenames containing ":" as they are not supported on Windows
|
||||
//!
|
||||
//! Only files added to git are checked, as it may be acceptable to have temporary
|
||||
//! invalid filenames in the local directory during development.
|
||||
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn check(root_path: &Path, bad: &mut bool) {
|
||||
let stat_output = Command::new("git")
|
||||
.arg("-C")
|
||||
.arg(root_path)
|
||||
.args(["ls-files", "-z"])
|
||||
.output()
|
||||
.unwrap()
|
||||
.stdout;
|
||||
for filename in stat_output.split(|&b| b == 0) {
|
||||
match str::from_utf8(filename) {
|
||||
Err(_) => tidy_error!(
|
||||
bad,
|
||||
r#"non-UTF8 file names are not supported: "{}""#,
|
||||
String::from_utf8_lossy(filename),
|
||||
),
|
||||
Ok(name) if name.chars().any(|c| c.is_control()) => tidy_error!(
|
||||
bad,
|
||||
r#"control characters are not supported in file names: "{}""#,
|
||||
String::from_utf8_lossy(filename),
|
||||
),
|
||||
Ok(name) if name.contains(':') => tidy_error!(
|
||||
bad,
|
||||
r#"":" is not supported in file names because of Windows compatibility: "{name}""#,
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -167,6 +167,7 @@ pub mod error_codes;
|
|||
pub mod ext_tool_checks;
|
||||
pub mod extdeps;
|
||||
pub mod features;
|
||||
pub mod filenames;
|
||||
pub mod fluent_alphabetical;
|
||||
pub mod fluent_period;
|
||||
mod fluent_used;
|
||||
|
|
|
|||
|
|
@ -155,6 +155,8 @@ fn main() {
|
|||
|
||||
check!(triagebot, &root_path);
|
||||
|
||||
check!(filenames, &root_path);
|
||||
|
||||
let collected = {
|
||||
drain_handles(&mut handles);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ impl Default for Manual {
|
|||
}
|
||||
}
|
||||
|
||||
//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]'
|
||||
//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["automatically_derived"]'
|
||||
//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
//@ is "$.index[?(@.name=='cold_fn')].attrs" '["#[attr = Cold]"]'
|
||||
//@ is "$.index[?(@.name=='cold_fn')].attrs" '[{"other": "#[attr = Cold]"}]'
|
||||
#[cold]
|
||||
pub fn cold_fn() {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@ edition: 2021
|
||||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]'
|
||||
#[export_name = "altered"]
|
||||
pub extern "C" fn example() {}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
#![no_std]
|
||||
|
||||
// The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024
|
||||
// is still `#[export_name = ..]` without the `unsafe` attribute wrapper.
|
||||
// doesn't mention the `unsafe`.
|
||||
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]'
|
||||
#[unsafe(export_name = "altered")]
|
||||
pub extern "C" fn example() {}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[attr = Inline(Hint)]"]'
|
||||
//@ is "$.index[?(@.name=='just_inline')].attrs" '[{"other": "#[attr = Inline(Hint)]"}]'
|
||||
#[inline]
|
||||
pub fn just_inline() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[attr = Inline(Always)]"]'
|
||||
//@ is "$.index[?(@.name=='inline_always')].attrs" '[{"other": "#[attr = Inline(Always)]"}]'
|
||||
#[inline(always)]
|
||||
pub fn inline_always() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[attr = Inline(Never)]"]'
|
||||
//@ is "$.index[?(@.name=='inline_never')].attrs" '[{"other": "#[attr = Inline(Never)]"}]'
|
||||
#[inline(never)]
|
||||
pub fn inline_never() {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//@ edition: 2021
|
||||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
|
||||
//@ count "$.index[?(@.name=='example')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"'
|
||||
#[link_section = ".text"]
|
||||
pub extern "C" fn example() {}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
// Since the 2024 edition the link_section attribute must use the unsafe qualification.
|
||||
// However, the unsafe qualification is not shown by rustdoc.
|
||||
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
|
||||
//@ count "$.index[?(@.name=='example')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"'
|
||||
#[unsafe(link_section = ".text")]
|
||||
pub extern "C" fn example() {}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["#[attr = MustUse]"]'
|
||||
//@ is "$.index[?(@.name=='example')].attrs[*].must_use.reason" null
|
||||
#[must_use]
|
||||
pub fn example() -> impl Iterator<Item = i64> {}
|
||||
|
||||
//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[attr = MustUse {reason: \"does nothing if you do not use it\"}]"]'
|
||||
//@ is "$.index[?(@.name=='explicit_message')].attrs[*].must_use.reason" '"does nothing if you do not use it"'
|
||||
#[must_use = "does nothing if you do not use it"]
|
||||
pub fn explicit_message() -> impl Iterator<Item = i64> {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@ edition: 2021
|
||||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]'
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]'
|
||||
#[no_mangle]
|
||||
pub extern "C" fn example() {}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
// The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024
|
||||
// is still `#[no_mangle]` without the `unsafe` attribute wrapper.
|
||||
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]'
|
||||
//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]'
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn example() {}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]'
|
||||
//@ is "$.index[?(@.name=='MyEnum')].attrs" '["non_exhaustive"]'
|
||||
#[non_exhaustive]
|
||||
pub enum MyEnum {
|
||||
First,
|
||||
}
|
||||
|
||||
pub enum NonExhaustiveVariant {
|
||||
//@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]'
|
||||
//@ is "$.index[?(@.name=='Variant')].attrs" '["non_exhaustive"]'
|
||||
#[non_exhaustive]
|
||||
Variant(i64),
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]'
|
||||
//@ is "$.index[?(@.name=='MyStruct')].attrs" '["non_exhaustive"]'
|
||||
#[non_exhaustive]
|
||||
pub struct MyStruct {
|
||||
pub x: i64,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#![feature(optimize_attribute)]
|
||||
|
||||
//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]'
|
||||
//@ is "$.index[?(@.name=='speed')].attrs" '[{"other": "#[attr = Optimize(Speed)]"}]'
|
||||
#[optimize(speed)]
|
||||
pub fn speed() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]'
|
||||
//@ is "$.index[?(@.name=='size')].attrs" '[{"other": "#[attr = Optimize(Size)]"}]'
|
||||
#[optimize(size)]
|
||||
pub fn size() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]'
|
||||
//@ is "$.index[?(@.name=='none')].attrs" '[{"other": "#[attr = Optimize(DoNotOptimize)]"}]'
|
||||
#[optimize(none)]
|
||||
pub fn none() {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]'
|
||||
//@ count "$.index[?(@.name=='Aligned')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='Aligned')].attrs[*].repr.align" 4
|
||||
#[repr(align(4))]
|
||||
pub struct Aligned {
|
||||
a: i8,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,28 @@
|
|||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]'
|
||||
//@ count "$.index[?(@.name=='ReprCStruct')].attrs" 1
|
||||
//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.kind" '"c"'
|
||||
//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.int" null
|
||||
//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.packed" null
|
||||
//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.align" null
|
||||
#[repr(C)]
|
||||
pub struct ReprCStruct(pub i64);
|
||||
|
||||
//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]'
|
||||
//@ count "$.index[?(@.name=='ReprCEnum')].attrs" 1
|
||||
//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.kind" '"c"'
|
||||
//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.int" null
|
||||
//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.packed" null
|
||||
//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.align" null
|
||||
#[repr(C)]
|
||||
pub enum ReprCEnum {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]'
|
||||
//@ count "$.index[?(@.name=='ReprCUnion')].attrs" 1
|
||||
//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.kind" '"c"'
|
||||
//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.int" null
|
||||
//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.packed" null
|
||||
//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.align" null
|
||||
#[repr(C)]
|
||||
pub union ReprCUnion {
|
||||
pub left: i64,
|
||||
|
|
|
|||
11
tests/rustdoc-json/attrs/repr_c_int_enum.rs
Normal file
11
tests/rustdoc-json/attrs/repr_c_int_enum.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//@ count "$.index[?(@.name=='Foo')].attrs" 1
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.kind" '"c"'
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u8"'
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.packed" null
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.align" 16
|
||||
#[repr(C, u8)]
|
||||
#[repr(align(16))]
|
||||
pub enum Foo {
|
||||
A(bool) = b'A',
|
||||
B(char) = b'C',
|
||||
}
|
||||
|
|
@ -1,35 +1,34 @@
|
|||
#![no_std]
|
||||
|
||||
// Combinations of `#[repr(..)]` attributes.
|
||||
// Rustdoc JSON emits normalized output, regardless of the original source.
|
||||
|
||||
//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]'
|
||||
//@ is "$.index[?(@.name=='ReprCI8')].attrs" '[{"repr":{"align":null,"int":"i8","kind":"c","packed":null}}]'
|
||||
#[repr(C, i8)]
|
||||
pub enum ReprCI8 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]'
|
||||
//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '[{"repr":{"align":null,"int":"i16","kind":"c","packed":null}}]'
|
||||
#[repr(C)]
|
||||
#[repr(i16)]
|
||||
pub enum SeparateReprCI16 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]'
|
||||
//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '[{"repr":{"align":null,"int":"usize","kind":"c","packed":null}}]'
|
||||
#[repr(usize, C)]
|
||||
pub enum ReversedReprCUsize {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]'
|
||||
//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":1}}]'
|
||||
#[repr(C, packed)]
|
||||
pub struct ReprCPacked {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]'
|
||||
//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]'
|
||||
#[repr(C)]
|
||||
#[repr(packed(2))]
|
||||
pub struct SeparateReprCPacked {
|
||||
|
|
@ -37,21 +36,21 @@ pub struct SeparateReprCPacked {
|
|||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]'
|
||||
//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]'
|
||||
#[repr(packed(2), C)]
|
||||
pub struct ReversedReprCPacked {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]'
|
||||
//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '[{"repr":{"align":16,"int":null,"kind":"c","packed":null}}]'
|
||||
#[repr(C, align(16))]
|
||||
pub struct ReprCAlign {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]'
|
||||
//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]'
|
||||
#[repr(C)]
|
||||
#[repr(align(2))]
|
||||
pub struct SeparateReprCAlign {
|
||||
|
|
@ -59,25 +58,25 @@ pub struct SeparateReprCAlign {
|
|||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]'
|
||||
//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]'
|
||||
#[repr(align(2), C)]
|
||||
pub struct ReversedReprCAlign {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]'
|
||||
//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]'
|
||||
#[repr(C, align(16), isize)]
|
||||
pub enum AlignedExplicitRepr {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]'
|
||||
//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]'
|
||||
#[repr(isize, C, align(16))]
|
||||
pub enum ReorderedAlignedExplicitRepr {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]'
|
||||
//@ is "$.index[?(@.name=='Transparent')].attrs" '[{"repr":{"align":null,"int":null,"kind":"transparent","packed":null}}]'
|
||||
#[repr(transparent)]
|
||||
pub struct Transparent(i64);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,27 @@
|
|||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]'
|
||||
//@ is "$.index[?(@.name=='I8')].attrs[*].repr.int" '"i8"'
|
||||
//@ is "$.index[?(@.name=='I8')].attrs[*].repr.kind" '"rust"'
|
||||
//@ is "$.index[?(@.name=='I8')].attrs[*].repr.align" null
|
||||
//@ is "$.index[?(@.name=='I8')].attrs[*].repr.packed" null
|
||||
#[repr(i8)]
|
||||
pub enum I8 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]'
|
||||
//@ is "$.index[?(@.name=='I32')].attrs[*].repr.int" '"i32"'
|
||||
//@ is "$.index[?(@.name=='I32')].attrs[*].repr.kind" '"rust"'
|
||||
//@ is "$.index[?(@.name=='I32')].attrs[*].repr.align" null
|
||||
//@ is "$.index[?(@.name=='I32')].attrs[*].repr.packed" null
|
||||
#[repr(i32)]
|
||||
pub enum I32 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]'
|
||||
//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.int" '"usize"'
|
||||
//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.kind" '"rust"'
|
||||
//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.align" null
|
||||
//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.packed" null
|
||||
#[repr(usize)]
|
||||
pub enum Usize {
|
||||
First,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
#![no_std]
|
||||
|
||||
// Note the normalization:
|
||||
// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON.
|
||||
// `#[repr(packed)]` in source becomes `{"repr": {"packed": 1, ...}}` in rustdoc JSON.
|
||||
//
|
||||
//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]'
|
||||
//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.packed" 1
|
||||
//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.kind" '"rust"'
|
||||
#[repr(packed)]
|
||||
pub struct Packed {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]'
|
||||
//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.packed" 4
|
||||
//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.kind" '"rust"'
|
||||
#[repr(packed(4))]
|
||||
pub struct PackedAligned {
|
||||
a: i8,
|
||||
|
|
|
|||
|
|
@ -1,38 +1,49 @@
|
|||
//@ is "$.index[?(@.name=='test1')].attrs" '["#[target_feature(enable=\"avx\")]"]'
|
||||
//@ is "$.index[?(@.name=='test1')].inner.function.header.is_unsafe" false
|
||||
//@ count "$.index[?(@.name=='test1')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='test1')].attrs[*].target_feature.enable" '["avx"]'
|
||||
#[target_feature(enable = "avx")]
|
||||
pub fn test1() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='test2')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]'
|
||||
//@ is "$.index[?(@.name=='test2')].inner.function.header.is_unsafe" false
|
||||
//@ count "$.index[?(@.name=='test2')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='test2')].attrs[*].target_feature.enable" '["avx", "avx2"]'
|
||||
#[target_feature(enable = "avx,avx2")]
|
||||
pub fn test2() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='test3')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]'
|
||||
//@ is "$.index[?(@.name=='test3')].inner.function.header.is_unsafe" false
|
||||
//@ count "$.index[?(@.name=='test3')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='test3')].attrs[*].target_feature.enable" '["avx", "avx2"]'
|
||||
#[target_feature(enable = "avx", enable = "avx2")]
|
||||
pub fn test3() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='test4')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\", enable=\"avx512f\")]"]'
|
||||
//@ is "$.index[?(@.name=='test4')].inner.function.header.is_unsafe" false
|
||||
//@ count "$.index[?(@.name=='test4')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='test4')].attrs[*].target_feature.enable" '["avx", "avx2", "avx512f"]'
|
||||
#[target_feature(enable = "avx", enable = "avx2,avx512f")]
|
||||
pub fn test4() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]'
|
||||
//@ count "$.index[?(@.name=='test5')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='test5')].attrs[*].target_feature.enable" '["avx", "avx2"]'
|
||||
#[target_feature(enable = "avx")]
|
||||
#[target_feature(enable = "avx2")]
|
||||
pub fn test5() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='test_unsafe_fn')].inner.function.header.is_unsafe" true
|
||||
//@ count "$.index[?(@.name=='test_unsafe_fn')].attrs[*]" 1
|
||||
//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs[*].target_feature.enable" '["avx"]'
|
||||
#[target_feature(enable = "avx")]
|
||||
pub unsafe fn test_unsafe_fn() {}
|
||||
|
||||
pub struct Example;
|
||||
|
||||
impl Example {
|
||||
//@ is "$.index[?(@.name=='safe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]'
|
||||
//@ is "$.index[?(@.name=='safe_assoc_fn')].inner.function.header.is_unsafe" false
|
||||
//@ is "$.index[?(@.name=='safe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]'
|
||||
#[target_feature(enable = "avx")]
|
||||
pub fn safe_assoc_fn() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]'
|
||||
//@ is "$.index[?(@.name=='unsafe_assoc_fn')].inner.function.header.is_unsafe" true
|
||||
//@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]'
|
||||
#[target_feature(enable = "avx")]
|
||||
pub unsafe fn unsafe_assoc_fn() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#[repr(i32)]
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"i32"'
|
||||
pub enum Foo {
|
||||
//@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null
|
||||
//@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#[repr(u32)]
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
|
||||
//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u32"'
|
||||
pub enum Foo {
|
||||
//@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null
|
||||
//@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
//@ !has "$.index[?(@.name=='match')]"
|
||||
//@ has "$.index[?(@.name=='foo')]"
|
||||
//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]'
|
||||
//@ is "$.index[?(@.name=='foo')].attrs[*].other" '"#[doc(keyword = \"match\")]"'
|
||||
//@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"'
|
||||
#[doc(keyword = "match")]
|
||||
/// this is a test!
|
||||
|
|
@ -13,7 +13,7 @@ pub mod foo {}
|
|||
|
||||
//@ !has "$.index[?(@.name=='break')]"
|
||||
//@ has "$.index[?(@.name=='bar')]"
|
||||
//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]'
|
||||
//@ is "$.index[?(@.name=='bar')].attrs[*].other" '"#[doc(keyword = \"break\")]"'
|
||||
//@ is "$.index[?(@.name=='bar')].docs" '"hello"'
|
||||
#[doc(keyword = "break")]
|
||||
/// hello
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
//@ compile-flags: --document-hidden-items
|
||||
#![no_std]
|
||||
|
||||
//@ is "$.index[?(@.name=='func')].attrs" '["#[doc(hidden)]"]'
|
||||
//@ is "$.index[?(@.name=='func')].attrs" '[{"other": "#[doc(hidden)]"}]'
|
||||
#[doc(hidden)]
|
||||
pub fn func() {}
|
||||
|
||||
//@ is "$.index[?(@.name=='Unit')].attrs" '["#[doc(hidden)]"]'
|
||||
//@ is "$.index[?(@.name=='Unit')].attrs" '[{"other": "#[doc(hidden)]"}]'
|
||||
#[doc(hidden)]
|
||||
pub struct Unit;
|
||||
|
||||
//@ is "$.index[?(@.name=='hidden')].attrs" '["#[doc(hidden)]"]'
|
||||
//@ is "$.index[?(@.name=='hidden')].attrs" '[{"other": "#[doc(hidden)]"}]'
|
||||
#[doc(hidden)]
|
||||
pub mod hidden {
|
||||
//@ is "$.index[?(@.name=='Inner')].attrs" '[]'
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
//@ known-bug: #110395
|
||||
#![feature(const_index, const_trait_impl)]
|
||||
|
||||
const A: [(); 5] = [(), (), (), (), ()];
|
||||
|
||||
// Since the indexing is on a ZST, the addresses are all fine,
|
||||
// but we should still catch the bad range.
|
||||
const B: &[()] = unsafe { A.get_unchecked(3..1) };
|
||||
//~^ ERROR: slice::get_unchecked requires that the range is within the slice
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error[E0015]: cannot call non-const method `core::slice::<impl [()]>::get_unchecked::<std::ops::Range<usize>>` in constants
|
||||
--> $DIR/ub-slice-get-unchecked.rs:7:29
|
||||
error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the range is within the slice
|
||||
|
||||
This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
|
||||
--> $DIR/ub-slice-get-unchecked.rs:7:27
|
||||
|
|
||||
LL | const B: &[()] = unsafe { A.get_unchecked(3..1) };
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ evaluation of `B` failed here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0015`.
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ struct Foo<'a> {
|
|||
impl<'a> Foo<'a> {
|
||||
const fn spam(&mut self, baz: &mut Vec<u32>) {
|
||||
self.bar[0] = baz.len();
|
||||
//~^ ERROR: cannot call
|
||||
//~^ ERROR: `Vec<usize>: [const] Index<_>` is not satisfied
|
||||
//~| ERROR: `Vec<usize>: [const] Index<usize>` is not satisfied
|
||||
//~| ERROR: `Vec<usize>: [const] IndexMut<usize>` is not satisfied
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,24 @@
|
|||
error[E0015]: cannot call non-const operator in constant functions
|
||||
--> $DIR/issue-94675.rs:9:17
|
||||
error[E0277]: the trait bound `Vec<usize>: [const] Index<_>` is not satisfied
|
||||
--> $DIR/issue-94675.rs:9:9
|
||||
|
|
||||
LL | self.bar[0] = baz.len();
|
||||
| ^^^
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `Vec<usize>: [const] IndexMut<usize>` is not satisfied
|
||||
--> $DIR/issue-94675.rs:9:9
|
||||
|
|
||||
note: impl defined here, but it is not `const`
|
||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
LL | self.bar[0] = baz.len();
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0277]: the trait bound `Vec<usize>: [const] Index<usize>` is not satisfied
|
||||
--> $DIR/issue-94675.rs:9:9
|
||||
|
|
||||
LL | self.bar[0] = baz.len();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: required by a bound in `std::ops::IndexMut::index_mut`
|
||||
--> $SRC_DIR/core/src/ops/index.rs:LL:COL
|
||||
|
||||
For more information about this error, try `rustc --explain E0015`.
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
|
|
@ -5,17 +5,17 @@ use std::ptr;
|
|||
//@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes"
|
||||
|
||||
|
||||
pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR
|
||||
pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR
|
||||
pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR
|
||||
pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR: is at the beginning of the allocation
|
||||
pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR: only 1 byte from the end of the allocation
|
||||
pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR: only 100 bytes from the end of the allocation
|
||||
|
||||
pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR
|
||||
pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR
|
||||
pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR: does not fit in an `isize`
|
||||
pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR: does not fit in an `isize`
|
||||
pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~ ERROR
|
||||
pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~ ERROR
|
||||
pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR
|
||||
pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR: before the beginning of the allocation
|
||||
|
||||
pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR
|
||||
pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR: at or beyond the end of the allocation
|
||||
pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; //~ ERROR
|
||||
|
||||
// Make sure that we don't panic when computing abs(offset*size_of::<T>())
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer
|
|||
LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ADDRESS_SPACE` failed here
|
||||
|
||||
error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation
|
||||
error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which points to before the beginning of the allocation
|
||||
--> $DIR/offset_ub.rs:16:49
|
||||
|
|
||||
LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here
|
||||
LL | ...*const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here
|
||||
|
||||
error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes
|
||||
--> $DIR/offset_ub.rs:18:50
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@ edition:2018
|
||||
#![crate_type = "lib"]
|
||||
#![feature(type_ascription)]
|
||||
#![feature(type_ascription, const_index, const_trait_impl)]
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
|
|
@ -129,7 +129,6 @@ pub fn inside_block() {
|
|||
|
||||
static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
|
||||
//~^ ERROR: cast cannot be followed by indexing
|
||||
//~| ERROR: cannot call non-const operator in statics
|
||||
|
||||
static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]);
|
||||
//~^ ERROR: expected one of
|
||||
|
|
|
|||
|
|
@ -219,13 +219,13 @@ LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]);
|
|||
| + +
|
||||
|
||||
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `:`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:134:36
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:133:36
|
||||
|
|
||||
LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]);
|
||||
| ^ expected one of `)`, `,`, `.`, `?`, or an operator
|
||||
|
||||
error: cast cannot be followed by `?`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:139:5
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:138:5
|
||||
|
|
||||
LL | Err(0u64) as Result<u64,u64>?;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -236,25 +236,25 @@ LL | (Err(0u64) as Result<u64,u64>)?;
|
|||
| + +
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:141:14
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:140:14
|
||||
|
|
||||
LL | Err(0u64): Result<u64,u64>?;
|
||||
| ^ expected one of `.`, `;`, `?`, `}`, or an operator
|
||||
|
||||
error: expected identifier, found `:`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:153:13
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:152:13
|
||||
|
|
||||
LL | drop_ptr: F();
|
||||
| ^ expected identifier
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:160:13
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:159:13
|
||||
|
|
||||
LL | drop_ptr: fn(u8);
|
||||
| ^ expected one of 8 possible tokens
|
||||
|
||||
error: cast cannot be followed by a function call
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:166:5
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:165:5
|
||||
|
|
||||
LL | drop as fn(u8)(0);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
@ -265,13 +265,13 @@ LL | (drop as fn(u8))(0);
|
|||
| + +
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:168:13
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:167:13
|
||||
|
|
||||
LL | drop_ptr: fn(u8)(0);
|
||||
| ^ expected one of 8 possible tokens
|
||||
|
||||
error: cast cannot be followed by `.await`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:173:5
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:172:5
|
||||
|
|
||||
LL | Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>.await;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -282,13 +282,13 @@ LL | (Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>).await;
|
|||
| + +
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:176:21
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:175:21
|
||||
|
|
||||
LL | Box::pin(noop()): Pin<Box<_>>.await;
|
||||
| ^ expected one of `.`, `;`, `?`, `}`, or an operator
|
||||
|
||||
error: cast cannot be followed by a field access
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:188:5
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:187:5
|
||||
|
|
||||
LL | Foo::default() as Foo.bar;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -299,7 +299,7 @@ LL | (Foo::default() as Foo).bar;
|
|||
| + +
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:190:19
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:189:19
|
||||
|
|
||||
LL | Foo::default(): Foo.bar;
|
||||
| ^ expected one of `.`, `;`, `?`, `}`, or an operator
|
||||
|
|
@ -322,21 +322,11 @@ LL | if true { 33 } else { 44 }: i32.max(0)
|
|||
| ^ expected one of `,`, `.`, `?`, or an operator
|
||||
|
||||
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:151:13
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:150:13
|
||||
|
|
||||
LL | drop as F();
|
||||
| ^^^ only `Fn` traits may use parentheses
|
||||
|
||||
error[E0015]: cannot call non-const operator in statics
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:130:42
|
||||
|
|
||||
LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
|
||||
error: aborting due to 39 previous errors
|
||||
|
||||
error: aborting due to 40 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0015, E0214.
|
||||
For more information about an error, try `rustc --explain E0015`.
|
||||
For more information about this error, try `rustc --explain E0214`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue