Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-11-03 05:18:08 +00:00
commit b58cbe2361
151 changed files with 852 additions and 1526 deletions

View File

@ -118,8 +118,8 @@ pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
GlobalAsmConfig {
assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"),
target: match &tcx.sess.opts.target_triple {
rustc_target::spec::TargetTriple::TargetTriple(triple) => triple.clone(),
rustc_target::spec::TargetTriple::TargetJson { path_for_rustdoc, .. } => {
rustc_target::spec::TargetTuple::TargetTuple(triple) => triple.clone(),
rustc_target::spec::TargetTuple::TargetJson { path_for_rustdoc, .. } => {
path_for_rustdoc.to_str().unwrap().to_owned()
}
},

View File

@ -146,7 +146,7 @@ fn codegen_static(&self, def_id: DefId) {
// Wasm statics with custom link sections get special treatment as they
// go into custom sections of the wasm executable.
if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
if self.tcx.sess.opts.target_triple.tuple().starts_with("wasm32") {
if let Some(_section) = attrs.link_section {
unimplemented!();
}

View File

@ -946,7 +946,7 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data:
}
fn target_is_apple(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
let triple = cgcx.opts.target_triple.triple();
let triple = cgcx.opts.target_triple.tuple();
triple.contains("-ios")
|| triple.contains("-darwin")
|| triple.contains("-tvos")
@ -955,7 +955,7 @@ fn target_is_apple(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
}
fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
cgcx.opts.target_triple.triple().contains("-aix")
cgcx.opts.target_triple.tuple().contains("-aix")
}
pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static CStr {
@ -1031,7 +1031,7 @@ unsafe fn embed_bitcode(
let is_aix = target_is_aix(cgcx);
let is_apple = target_is_apple(cgcx);
unsafe {
if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") {
if is_apple || is_aix || cgcx.opts.target_triple.tuple().starts_with("wasm") {
// We don't need custom section flags, create LLVM globals.
let llconst = common::bytes_in_context(llcx, bitcode);
let llglobal = llvm::LLVMAddGlobal(

View File

@ -997,7 +997,7 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
{
let is_vs_installed = windows_registry::find_vs_version().is_ok();
let has_linker = windows_registry::find_tool(
sess.opts.target_triple.triple(),
sess.opts.target_triple.tuple(),
"link.exe",
)
.is_some();
@ -1323,10 +1323,8 @@ fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
} else {
let default_sysroot =
filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
let default_tlib = filesearch::make_target_lib_path(
&default_sysroot,
sess.opts.target_triple.triple(),
);
let default_tlib =
filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.tuple());
default_tlib
}
}

View File

@ -47,7 +47,7 @@ pub(crate) fn get_linker<'a>(
self_contained: bool,
target_cpu: &'a str,
) -> Box<dyn Linker + 'a> {
let msvc_tool = windows_registry::find_tool(sess.opts.target_triple.triple(), "link.exe");
let msvc_tool = windows_registry::find_tool(sess.opts.target_triple.tuple(), "link.exe");
// If our linker looks like a batch script on Windows then to execute this
// we'll need to spawn `cmd` explicitly. This is primarily done to handle

View File

@ -1,9 +1,6 @@
const_eval_address_space_full =
there are no more free addresses in the address space
const_eval_align_offset_invalid_align =
`align_offset` called with non-power-of-two align: {$target_align}
const_eval_alignment_check_failed =
{$msg ->
[AccessedPtr] accessing memory

View File

@ -1,7 +1,6 @@
use std::borrow::{Borrow, Cow};
use std::fmt;
use std::hash::Hash;
use std::ops::ControlFlow;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
@ -9,7 +8,7 @@
use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
use rustc_middle::mir::AssertMessage;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_span::Span;
@ -23,9 +22,9 @@
use crate::fluent_generated as fluent;
use crate::interpret::{
self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy,
InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, RangeSet, Scalar,
StackPopCleanup, compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub,
throw_ub_custom, throw_unsup, throw_unsup_format,
InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, RangeSet, Scalar, compile_time_machine,
interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup,
throw_unsup_format,
};
/// When hitting this many interpreted terminators we emit a deny by default lint
@ -227,8 +226,8 @@ fn hook_special_const_fn(
&mut self,
instance: ty::Instance<'tcx>,
args: &[FnArg<'tcx>],
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
_dest: &MPlaceTy<'tcx>,
_ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
let def_id = instance.def_id();
@ -260,85 +259,10 @@ fn hook_special_const_fn(
);
return interp_ok(Some(new_instance));
} else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) {
let args = self.copy_fn_args(args);
// For align_offset, we replace the function call if the pointer has no address.
match self.align_offset(instance, &args, dest, ret)? {
ControlFlow::Continue(()) => return interp_ok(Some(instance)),
ControlFlow::Break(()) => return interp_ok(None),
}
}
interp_ok(Some(instance))
}
/// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer
/// may not have an address.
///
/// If `ptr` does have a known address, then we return `Continue(())` and the function call should
/// proceed as normal.
///
/// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most
/// `target_align`, then we call the function again with an dummy address relative to the
/// allocation.
///
/// If `ptr` doesn't have an address and `target_align` is stricter than the underlying
/// allocation's alignment, then we return `usize::MAX` immediately.
fn align_offset(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx, ControlFlow<()>> {
assert_eq!(args.len(), 2);
let ptr = self.read_pointer(&args[0])?;
let target_align = self.read_scalar(&args[1])?.to_target_usize(self)?;
if !target_align.is_power_of_two() {
throw_ub_custom!(
fluent::const_eval_align_offset_invalid_align,
target_align = target_align,
);
}
match self.ptr_try_get_alloc_id(ptr, 0) {
Ok((alloc_id, offset, _extra)) => {
let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id);
if target_align <= alloc_align.bytes() {
// Extract the address relative to the allocation base that is definitely
// sufficiently aligned and call `align_offset` again.
let addr = ImmTy::from_uint(offset.bytes(), args[0].layout).into();
let align = ImmTy::from_uint(target_align, args[1].layout).into();
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
// Push the stack frame with our own adjusted arguments.
self.init_stack_frame(
instance,
self.load_mir(instance.def, None)?,
fn_abi,
&[FnArg::Copy(addr), FnArg::Copy(align)],
/* with_caller_location = */ false,
dest,
StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable },
)?;
interp_ok(ControlFlow::Break(()))
} else {
// Not alignable in const, return `usize::MAX`.
let usize_max = Scalar::from_target_usize(self.target_usize_max(), self);
self.write_scalar(usize_max, dest)?;
self.return_to_block(ret)?;
interp_ok(ControlFlow::Break(()))
}
}
Err(_addr) => {
// The pointer has an address, continue with function call.
interp_ok(ControlFlow::Continue(()))
}
}
}
/// See documentation on the `ptr_guaranteed_cmp` intrinsic.
fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
interp_ok(match (a, b) {

View File

@ -62,7 +62,7 @@
use rustc_span::FileName;
use rustc_span::source_map::FileLoader;
use rustc_target::json::ToJson;
use rustc_target::spec::{Target, TargetTriple};
use rustc_target::spec::{Target, TargetTuple};
use time::OffsetDateTime;
use tracing::trace;
@ -731,6 +731,7 @@ fn print_crate_info(
targets.sort_unstable();
println_info!("{}", targets.join("\n"));
}
HostTuple => println_info!("{}", rustc_session::config::host_tuple()),
Sysroot => println_info!("{}", sess.sysroot.display()),
TargetLibdir => println_info!("{}", sess.target_tlib_path.dir.display()),
TargetSpec => {
@ -739,7 +740,7 @@ fn print_crate_info(
AllTargetSpecs => {
let mut targets = BTreeMap::new();
for name in rustc_target::spec::TARGETS {
let triple = TargetTriple::from_triple(name);
let triple = TargetTuple::from_tuple(name);
let target = Target::expect_builtin(&triple);
targets.insert(name, target.to_json());
}
@ -918,7 +919,7 @@ pub fn version_at_macro_invocation(
safe_println!("binary: {binary}");
safe_println!("commit-hash: {commit_hash}");
safe_println!("commit-date: {commit_date}");
safe_println!("host: {}", config::host_triple());
safe_println!("host: {}", config::host_tuple());
safe_println!("release: {release}");
let debug_flags = matches.opt_strs("Z");
@ -1495,7 +1496,7 @@ fn report_ice(
}
let version = util::version_str!().unwrap_or("unknown_version");
let triple = config::host_triple();
let tuple = config::host_tuple();
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
@ -1505,7 +1506,7 @@ fn report_ice(
Ok(mut file) => {
dcx.emit_note(session_diagnostics::IcePath { path: path.clone() });
if FIRST_PANIC.swap(false, Ordering::SeqCst) {
let _ = write!(file, "\n\nrustc version: {version}\nplatform: {triple}");
let _ = write!(file, "\n\nrustc version: {version}\nplatform: {tuple}");
}
Some(file)
}
@ -1518,12 +1519,12 @@ fn report_ice(
.map(PathBuf::from)
.map(|env_var| session_diagnostics::IcePathErrorEnv { env_var }),
});
dcx.emit_note(session_diagnostics::IceVersion { version, triple });
dcx.emit_note(session_diagnostics::IceVersion { version, triple: tuple });
None
}
}
} else {
dcx.emit_note(session_diagnostics::IceVersion { version, triple });
dcx.emit_note(session_diagnostics::IceVersion { version, triple: tuple });
None
};

View File

@ -11,7 +11,7 @@
use rustc_span::Span;
use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTuple};
use rustc_type_ir::{ClosureKind, FloatTy};
use {rustc_ast as ast, rustc_hir as hir};
@ -89,7 +89,7 @@ fn into_diag_arg(self) -> DiagArgValue {
MacroRulesNormalizedIdent,
ParseIntError,
StackProtector,
&TargetTriple,
&TargetTuple,
SplitDebuginfo,
ExitStatus,
ErrCode,

View File

@ -348,9 +348,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None;
/// Align offset for stride != 1; must not panic.
AlignOffset, sym::align_offset, align_offset_fn, Target::Fn, GenericRequirement::None;
Termination, sym::termination, termination, Target::Trait, GenericRequirement::None;
Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None;

View File

@ -493,7 +493,7 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! {
"we would appreciate a joke overview: \
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
);
diag.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),));
diag.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_tuple(),));
if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() {
diag.note(format!("compiler flags: {}", flags.join(" ")));
if excluded_cargo_defaults {

View File

@ -11,7 +11,7 @@
use rustc_metadata::{DylibError, load_symbol_from_dylib};
use rustc_middle::ty::CurrentGcx;
use rustc_parse::validate_attr;
use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, host_triple};
use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, host_tuple};
use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
@ -310,7 +310,7 @@ fn get_codegen_sysroot(
"cannot load the default codegen backend twice"
);
let target = host_triple();
let target = host_tuple();
let sysroot_candidates = sysroot_candidates();
let sysroot = iter::once(sysroot)

View File

@ -30,7 +30,7 @@
use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, Symbol, sym};
use rustc_span::{DUMMY_SP, Span};
use rustc_target::spec::{PanicStrategy, Target, TargetTriple};
use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
use tracing::{debug, info, trace};
use crate::errors;
@ -506,7 +506,7 @@ fn load_proc_macro<'b>(
locator.reset();
locator.is_proc_macro = true;
locator.target = &self.sess.host;
locator.triple = TargetTriple::from_triple(config::host_triple());
locator.tuple = TargetTuple::from_tuple(config::host_tuple());
locator.filesearch = self.sess.host_filesearch(path_kind);
let Some(host_result) = self.load(locator)? else {
@ -635,7 +635,7 @@ fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, Cra
// FIXME: why is this condition necessary? It was adding in #33625 but I
// don't know why and the original author doesn't remember ...
let can_reuse_cratenum =
locator.triple == self.sess.opts.target_triple || locator.is_proc_macro;
locator.tuple == self.sess.opts.target_triple || locator.is_proc_macro;
Ok(Some(if can_reuse_cratenum {
let mut result = LoadResult::Loaded(library);
for (cnum, data) in self.cstore.iter_crate_data() {

View File

@ -5,7 +5,7 @@
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol, sym};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use rustc_target::spec::{PanicStrategy, TargetTuple};
use crate::fluent_generated as fluent;
use crate::locator::CrateFlavor;
@ -630,7 +630,7 @@ pub struct CannotFindCrate {
pub current_crate: String,
pub is_nightly_build: bool,
pub profiler_runtime: Symbol,
pub locator_triple: TargetTriple,
pub locator_triple: TargetTuple,
pub is_ui_testing: bool,
}
@ -641,7 +641,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
diag.arg("crate_name", self.crate_name);
diag.arg("current_crate", self.current_crate);
diag.arg("add_info", self.add_info);
diag.arg("locator_triple", self.locator_triple.triple());
diag.arg("locator_triple", self.locator_triple.tuple());
diag.code(E0463);
diag.span(self.span);
if self.crate_name == sym::std || self.crate_name == sym::core {

View File

@ -231,7 +231,7 @@
use rustc_session::utils::CanonicalizedPath;
use rustc_span::Span;
use rustc_span::symbol::Symbol;
use rustc_target::spec::{Target, TargetTriple};
use rustc_target::spec::{Target, TargetTuple};
use tracing::{debug, info};
use crate::creader::{Library, MetadataLoader};
@ -252,7 +252,7 @@ pub(crate) struct CrateLocator<'a> {
pub hash: Option<Svh>,
extra_filename: Option<&'a str>,
pub target: &'a Target,
pub triple: TargetTriple,
pub tuple: TargetTuple,
pub filesearch: FileSearch<'a>,
pub is_proc_macro: bool,
@ -338,7 +338,7 @@ pub(crate) fn new(
hash,
extra_filename,
target: &sess.target,
triple: sess.opts.target_triple.clone(),
tuple: sess.opts.target_triple.clone(),
filesearch: sess.target_filesearch(path_kind),
is_proc_macro: false,
crate_rejections: CrateRejections::default(),
@ -677,8 +677,8 @@ fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<S
return None;
}
if header.triple != self.triple {
info!("Rejecting via crate triple: expected {} got {}", self.triple, header.triple);
if header.triple != self.tuple {
info!("Rejecting via crate triple: expected {} got {}", self.tuple, header.triple);
self.crate_rejections.via_triple.push(CrateMismatch {
path: libpath.to_path_buf(),
got: header.triple.to_string(),
@ -766,7 +766,7 @@ pub(crate) fn into_error(self, root: Option<CratePaths>) -> CrateError {
CrateError::LocatorCombined(Box::new(CombinedLocatorError {
crate_name: self.crate_name,
root,
triple: self.triple,
triple: self.tuple,
dll_prefix: self.target.dll_prefix.to_string(),
dll_suffix: self.target.dll_suffix.to_string(),
crate_rejections: self.crate_rejections,
@ -909,7 +909,7 @@ struct CrateRejections {
pub(crate) struct CombinedLocatorError {
crate_name: Symbol,
root: Option<CratePaths>,
triple: TargetTriple,
triple: TargetTuple,
dll_prefix: String,
dll_suffix: String,
crate_rejections: CrateRejections,
@ -1034,7 +1034,7 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
dcx.emit_err(errors::NoCrateWithTriple {
span,
crate_name,
locator_triple: locator.triple.triple(),
locator_triple: locator.triple.tuple(),
add_info,
found_crates,
});

View File

@ -770,7 +770,7 @@ pub(crate) fn list_crate_metadata(
root.stable_crate_id
)?;
writeln!(out, "proc_macro {:?}", root.proc_macro_data.is_some())?;
writeln!(out, "triple {}", root.header.triple.triple())?;
writeln!(out, "triple {}", root.header.triple.tuple())?;
writeln!(out, "edition {}", root.edition)?;
writeln!(out, "symbol_mangling_version {:?}", root.symbol_mangling_version)?;
writeln!(

View File

@ -38,7 +38,7 @@
use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use rustc_target::spec::{PanicStrategy, TargetTuple};
use table::TableBuilder;
use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
@ -213,7 +213,7 @@ pub(crate) struct ProcMacroData {
/// If you do modify this struct, also bump the [`METADATA_VERSION`] constant.
#[derive(MetadataEncodable, MetadataDecodable)]
pub(crate) struct CrateHeader {
pub(crate) triple: TargetTriple,
pub(crate) triple: TargetTuple,
pub(crate) hash: Svh,
pub(crate) name: Symbol,
/// Whether this is the header for a proc-macro crate.

View File

@ -1,5 +1,7 @@
use std::borrow::Cow;
use std::fs::File;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::io::{Read, Write};
use std::path::PathBuf;
use rustc_errors::pluralize;
@ -250,8 +252,8 @@ pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option<PathBuf>) -> String
}
let width = self.sess.diagnostic_width();
let length_limit = width.saturating_sub(30);
if regular.len() <= width {
let length_limit = width / 2;
if regular.len() <= width * 2 / 3 {
return regular;
}
let short = self.ty_string_with_limit(ty, length_limit);
@ -265,7 +267,20 @@ pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option<PathBuf>) -> String
*path = Some(path.take().unwrap_or_else(|| {
self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None)
}));
match std::fs::write(path.as_ref().unwrap(), &format!("{regular}\n")) {
let Ok(mut file) =
File::options().create(true).read(true).append(true).open(&path.as_ref().unwrap())
else {
return regular;
};
// Do not write the same type to the file multiple times.
let mut contents = String::new();
let _ = file.read_to_string(&mut contents);
if let Some(_) = contents.lines().find(|line| line == &regular) {
return short;
}
match write!(file, "{regular}\n") {
Ok(_) => short,
Err(_) => regular,
}

View File

@ -26,7 +26,7 @@
FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm, Symbol, sym,
};
use rustc_target::spec::{
FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTriple,
FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple,
};
use tracing::debug;
@ -813,6 +813,7 @@ pub struct PrintRequest {
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PrintKind {
FileNames,
HostTuple,
Sysroot,
TargetLibdir,
CrateName,
@ -1116,7 +1117,7 @@ pub struct RemapPathScopeComponents: u8 {
}
}
pub fn host_triple() -> &'static str {
pub fn host_tuple() -> &'static str {
// Get the host triple out of the build environment. This ensures that our
// idea of the host triple is the same as for the set of libraries we've
// actually built. We can't just take LLVM's host triple because they
@ -1158,7 +1159,7 @@ fn default() -> Options {
output_types: OutputTypes(BTreeMap::new()),
search_paths: vec![],
maybe_sysroot: None,
target_triple: TargetTriple::from_triple(host_triple()),
target_triple: TargetTuple::from_tuple(host_tuple()),
test: false,
incremental: None,
untracked_state_hash: Default::default(),
@ -1354,7 +1355,7 @@ pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &
// rust-lang/compiler-team#695. Warn unconditionally on usage to
// raise awareness of the renaming. This code will be deleted in
// October 2024.
if opts.target_triple.triple() == "wasm32-wasi" {
if opts.target_triple.tuple() == "wasm32-wasi" {
early_dcx.early_warn(
"the `wasm32-wasi` target is being renamed to \
`wasm32-wasip1` and the `wasm32-wasi` target will be \
@ -1945,6 +1946,7 @@ fn collect_print_requests(
("crate-name", PrintKind::CrateName),
("deployment-target", PrintKind::DeploymentTarget),
("file-names", PrintKind::FileNames),
("host-tuple", PrintKind::HostTuple),
("link-args", PrintKind::LinkArgs),
("native-static-libs", PrintKind::NativeStaticLibs),
("relocation-models", PrintKind::RelocationModels),
@ -2030,16 +2032,16 @@ fn collect_print_requests(
prints
}
pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTriple {
pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple {
match matches.opt_str("target") {
Some(target) if target.ends_with(".json") => {
let path = Path::new(&target);
TargetTriple::from_path(path).unwrap_or_else(|_| {
TargetTuple::from_path(path).unwrap_or_else(|_| {
early_dcx.early_fatal(format!("target file {path:?} does not exist"))
})
}
Some(target) => TargetTriple::TargetTriple(target),
_ => TargetTriple::from_triple(host_triple()),
Some(target) => TargetTuple::TargetTuple(target),
_ => TargetTuple::from_tuple(host_tuple()),
}
}
@ -3009,7 +3011,7 @@ pub(crate) mod dep_tracking {
use rustc_span::edition::Edition;
use rustc_target::spec::{
CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTriple,
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
TlsModel, WasmCAbi,
};
@ -3094,7 +3096,7 @@ fn hash(
SanitizerSet,
CFGuard,
CFProtection,
TargetTriple,
TargetTuple,
Edition,
LinkerPluginLto,
ResolveDocLinks,

View File

@ -29,7 +29,7 @@
use rustc_lint_defs::BuiltinLintDiag;
use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS;
use rustc_span::symbol::{Symbol, sym};
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTriple};
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTuple};
use crate::Session;
use crate::config::{CrateType, FmtDebug};
@ -417,7 +417,7 @@ macro_rules! ins {
for target in TARGETS
.iter()
.map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
.map(|target| Target::expect_builtin(&TargetTuple::from_tuple(target)))
.chain(iter::once(current_target.clone()))
{
values_target_abi.insert(Symbol::intern(&target.options.abi));

View File

@ -9,7 +9,7 @@
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTuple};
use crate::config::CrateType;
use crate::parse::ParseSess;
@ -179,13 +179,13 @@ pub(crate) struct EmbedSourceInsufficientDwarfVersion {
#[diag(session_target_stack_protector_not_supported)]
pub(crate) struct StackProtectorNotSupportedForTarget<'a> {
pub(crate) stack_protector: StackProtector,
pub(crate) target_triple: &'a TargetTriple,
pub(crate) target_triple: &'a TargetTuple,
}
#[derive(Diagnostic)]
#[diag(session_target_small_data_threshold_not_supported)]
pub(crate) struct SmallDataThresholdNotSupportedForTarget<'a> {
pub(crate) target_triple: &'a TargetTriple,
pub(crate) target_triple: &'a TargetTuple,
}
#[derive(Diagnostic)]
@ -383,7 +383,7 @@ struct BinaryFloatLiteralNotSupported {
#[diag(session_unsupported_crate_type_for_target)]
pub(crate) struct UnsupportedCrateTypeForTarget<'a> {
pub(crate) crate_type: CrateType,
pub(crate) target_triple: &'a TargetTriple,
pub(crate) target_triple: &'a TargetTuple,
}
pub fn report_lit_error(

View File

@ -152,7 +152,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
}
pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
let target = crate::config::host_triple();
let target = crate::config::host_tuple();
let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
let path = current_dll_path().and_then(|s| try_canonicalize(s).map_err(|e| e.to_string()));
@ -218,7 +218,7 @@ fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
))?;
// if `dir` points target's dir, move up to the sysroot
let mut sysroot_dir = if dir.ends_with(crate::config::host_triple()) {
let mut sysroot_dir = if dir.ends_with(crate::config::host_tuple()) {
dir.parent() // chop off `$target`
.and_then(|p| p.parent()) // chop off `rustlib`
.and_then(|p| p.parent()) // chop off `lib`

View File

@ -14,7 +14,7 @@
use rustc_target::spec::{
CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
TargetTriple, TlsModel, WasmCAbi,
TargetTuple, TlsModel, WasmCAbi,
};
use crate::config::*;
@ -146,7 +146,7 @@ pub struct Options {
libs: Vec<NativeLib> [TRACKED],
maybe_sysroot: Option<PathBuf> [UNTRACKED],
target_triple: TargetTriple [TRACKED],
target_triple: TargetTuple [TRACKED],
/// Effective logical environment used by `env!`/`option_env!` macros
logical_env: FxIndexMap<String, String> [TRACKED],

View File

@ -1,7 +1,7 @@
use std::path::{Path, PathBuf};
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_target::spec::TargetTriple;
use rustc_target::spec::TargetTuple;
use crate::EarlyDiagCtxt;
use crate::filesearch::make_target_lib_path;
@ -52,7 +52,7 @@ pub fn matches(&self, kind: PathKind) -> bool {
impl SearchPath {
pub fn from_cli_opt(
sysroot: &Path,
triple: &TargetTriple,
triple: &TargetTuple,
early_dcx: &EarlyDiagCtxt,
path: &str,
is_unstable_enabled: bool,
@ -80,7 +80,7 @@ pub fn from_cli_opt(
);
}
make_target_lib_path(sysroot, triple.triple()).join("builtin").join(stripped)
make_target_lib_path(sysroot, triple.tuple()).join("builtin").join(stripped)
}
None => PathBuf::from(path),
};

View File

@ -32,7 +32,7 @@
use rustc_target::spec::{
CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target,
TargetTriple, TlsModel,
TargetTuple, TlsModel,
};
use crate::code_stats::CodeStats;
@ -451,12 +451,12 @@ pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
/// directories are also returned, for example if `--sysroot` is used but tools are missing
/// (#125246): we also add the bin directories to the sysroot where rustc is located.
pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
let bin_path = filesearch::make_target_bin_path(&self.sysroot, config::host_triple());
let bin_path = filesearch::make_target_bin_path(&self.sysroot, config::host_tuple());
let fallback_sysroot_paths = filesearch::sysroot_candidates()
.into_iter()
// Ignore sysroot candidate if it was the same as the sysroot path we just used.
.filter(|sysroot| *sysroot != self.sysroot)
.map(|sysroot| filesearch::make_target_bin_path(&sysroot, config::host_triple()));
.map(|sysroot| filesearch::make_target_bin_path(&sysroot, config::host_tuple()));
let search_paths = std::iter::once(bin_path).chain(fallback_sysroot_paths);
if self_contained {
@ -1023,7 +1023,7 @@ pub fn build_session(
let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow);
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
let host_triple = TargetTriple::from_triple(config::host_triple());
let host_triple = TargetTuple::from_tuple(config::host_tuple());
let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
early_dcx.early_fatal(format!("Error loading host specification: {e}"))
});
@ -1074,8 +1074,8 @@ pub fn build_session(
let mut psess = ParseSess::with_dcx(dcx, source_map);
psess.assume_incomplete_release = sopts.unstable_opts.assume_incomplete_release;
let host_triple = config::host_triple();
let target_triple = sopts.target_triple.triple();
let host_triple = config::host_tuple();
let target_triple = sopts.target_triple.tuple();
let host_tlib_path = Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, host_triple));
let target_tlib_path = if host_triple == target_triple {
// Use the same `SearchPath` if host and target triple are identical to avoid unnecessary

View File

@ -378,7 +378,6 @@
aggregate_raw_ptr,
alias,
align,
align_offset,
alignment,
all,
alloc,

View File

@ -1,21 +1,21 @@
//! [Flexible target specification.](https://github.com/rust-lang/rfcs/pull/131)
//!
//! Rust targets a wide variety of usecases, and in the interest of flexibility,
//! allows new target triples to be defined in configuration files. Most users
//! allows new target tuples to be defined in configuration files. Most users
//! will not need to care about these, but this is invaluable when porting Rust
//! to a new platform, and allows for an unprecedented level of control over how
//! the compiler works.
//!
//! # Using custom targets
//!
//! A target triple, as passed via `rustc --target=TRIPLE`, will first be
//! A target tuple, as passed via `rustc --target=TUPLE`, will first be
//! compared against the list of built-in targets. This is to ease distributing
//! rustc (no need for configuration files) and also to hold these built-in
//! targets as immutable and sacred. If `TRIPLE` is not one of the built-in
//! targets, rustc will check if a file named `TRIPLE` exists. If it does, it
//! targets as immutable and sacred. If `TUPLE` is not one of the built-in
//! targets, rustc will check if a file named `TUPLE` exists. If it does, it
//! will be loaded as the target configuration. If the file does not exist,
//! rustc will search each directory in the environment variable
//! `RUST_TARGET_PATH` for a file named `TRIPLE.json`. The first one found will
//! `RUST_TARGET_PATH` for a file named `TUPLE.json`. The first one found will
//! be loaded. If no file is found in any of those directories, a fatal error
//! will be given.
//!
@ -1586,17 +1586,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
macro_rules! supported_targets {
( $(($triple:literal, $module:ident),)+ ) => {
( $(($tuple:literal, $module:ident),)+ ) => {
mod targets {
$(pub(crate) mod $module;)+
}
/// List of supported targets
pub const TARGETS: &[&str] = &[$($triple),+];
pub const TARGETS: &[&str] = &[$($tuple),+];
fn load_builtin(target: &str) -> Option<Target> {
let mut t = match target {
$( $triple => targets::$module::target(), )+
$( $tuple => targets::$module::target(), )+
_ => return None,
};
t.is_builtin = true;
@ -2005,9 +2005,9 @@ pub fn warning_messages(&self) -> Vec<String> {
/// Every field here must be specified, and has no default value.
#[derive(PartialEq, Clone, Debug)]
pub struct Target {
/// Unversioned target triple to pass to LLVM.
/// Unversioned target tuple to pass to LLVM.
///
/// Target triples can optionally contain an OS version (notably Apple targets), which rustc
/// Target tuples can optionally contain an OS version (notably Apple targets), which rustc
/// cannot know without querying the environment.
///
/// Use `rustc_codegen_ssa::back::versioned_llvm_target` if you need the full LLVM target.
@ -3477,28 +3477,28 @@ macro_rules! key {
}
/// Load a built-in target
pub fn expect_builtin(target_triple: &TargetTriple) -> Target {
match *target_triple {
TargetTriple::TargetTriple(ref target_triple) => {
load_builtin(target_triple).expect("built-in target")
pub fn expect_builtin(target_tuple: &TargetTuple) -> Target {
match *target_tuple {
TargetTuple::TargetTuple(ref target_tuple) => {
load_builtin(target_tuple).expect("built-in target")
}
TargetTriple::TargetJson { .. } => {
TargetTuple::TargetJson { .. } => {
panic!("built-in targets doesn't support target-paths")
}
}
}
/// Search for a JSON file specifying the given target triple.
/// Search for a JSON file specifying the given target tuple.
///
/// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the
/// sysroot under the target-triple's `rustlib` directory. Note that it could also just be a
/// sysroot under the target-tuple's `rustlib` directory. Note that it could also just be a
/// bare filename already, so also check for that. If one of the hardcoded targets we know
/// about, just return it directly.
///
/// The error string could come from any of the APIs called, including filesystem access and
/// JSON decoding.
pub fn search(
target_triple: &TargetTriple,
target_tuple: &TargetTuple,
sysroot: &Path,
) -> Result<(Target, TargetWarnings), String> {
use std::{env, fs};
@ -3509,16 +3509,16 @@ fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
Target::from_json(obj)
}
match *target_triple {
TargetTriple::TargetTriple(ref target_triple) => {
// check if triple is in list of built-in targets
if let Some(t) = load_builtin(target_triple) {
match *target_tuple {
TargetTuple::TargetTuple(ref target_tuple) => {
// check if tuple is in list of built-in targets
if let Some(t) = load_builtin(target_tuple) {
return Ok((t, TargetWarnings::empty()));
}
// search for a file named `target_triple`.json in RUST_TARGET_PATH
// search for a file named `target_tuple`.json in RUST_TARGET_PATH
let path = {
let mut target = target_triple.to_string();
let mut target = target_tuple.to_string();
target.push_str(".json");
PathBuf::from(target)
};
@ -3532,9 +3532,9 @@ fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
}
}
// Additionally look in the sysroot under `lib/rustlib/<triple>/target.json`
// Additionally look in the sysroot under `lib/rustlib/<tuple>/target.json`
// as a fallback.
let rustlib_path = crate::relative_target_rustlib_path(sysroot, target_triple);
let rustlib_path = crate::relative_target_rustlib_path(sysroot, target_tuple);
let p = PathBuf::from_iter([
Path::new(sysroot),
Path::new(&rustlib_path),
@ -3544,9 +3544,9 @@ fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
return load_file(&p);
}
Err(format!("Could not find specification for target {target_triple:?}"))
Err(format!("Could not find specification for target {target_tuple:?}"))
}
TargetTriple::TargetJson { ref contents, .. } => {
TargetTuple::TargetJson { ref contents, .. } => {
let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
Target::from_json(obj)
}
@ -3751,44 +3751,44 @@ macro_rules! target_option_val {
}
}
/// Either a target triple string or a path to a JSON file.
/// Either a target tuple string or a path to a JSON file.
#[derive(Clone, Debug)]
pub enum TargetTriple {
TargetTriple(String),
pub enum TargetTuple {
TargetTuple(String),
TargetJson {
/// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
/// inconsistencies as it is discarded during serialization.
path_for_rustdoc: PathBuf,
triple: String,
tuple: String,
contents: String,
},
}
// Use a manual implementation to ignore the path field
impl PartialEq for TargetTriple {
impl PartialEq for TargetTuple {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0,
(Self::TargetTuple(l0), Self::TargetTuple(r0)) => l0 == r0,
(
Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents },
Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents },
) => l_triple == r_triple && l_contents == r_contents,
Self::TargetJson { path_for_rustdoc: _, tuple: l_tuple, contents: l_contents },
Self::TargetJson { path_for_rustdoc: _, tuple: r_tuple, contents: r_contents },
) => l_tuple == r_tuple && l_contents == r_contents,
_ => false,
}
}
}
// Use a manual implementation to ignore the path field
impl Hash for TargetTriple {
impl Hash for TargetTuple {
fn hash<H: Hasher>(&self, state: &mut H) -> () {
match self {
TargetTriple::TargetTriple(triple) => {
TargetTuple::TargetTuple(tuple) => {
0u8.hash(state);
triple.hash(state)
tuple.hash(state)
}
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => {
1u8.hash(state);
triple.hash(state);
tuple.hash(state);
contents.hash(state)
}
}
@ -3796,45 +3796,45 @@ fn hash<H: Hasher>(&self, state: &mut H) -> () {
}
// Use a manual implementation to prevent encoding the target json file path in the crate metadata
impl<S: Encoder> Encodable<S> for TargetTriple {
impl<S: Encoder> Encodable<S> for TargetTuple {
fn encode(&self, s: &mut S) {
match self {
TargetTriple::TargetTriple(triple) => {
TargetTuple::TargetTuple(tuple) => {
s.emit_u8(0);
s.emit_str(triple);
s.emit_str(tuple);
}
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => {
s.emit_u8(1);
s.emit_str(triple);
s.emit_str(tuple);
s.emit_str(contents);
}
}
}
}
impl<D: Decoder> Decodable<D> for TargetTriple {
impl<D: Decoder> Decodable<D> for TargetTuple {
fn decode(d: &mut D) -> Self {
match d.read_u8() {
0 => TargetTriple::TargetTriple(d.read_str().to_owned()),
1 => TargetTriple::TargetJson {
0 => TargetTuple::TargetTuple(d.read_str().to_owned()),
1 => TargetTuple::TargetJson {
path_for_rustdoc: PathBuf::new(),
triple: d.read_str().to_owned(),
tuple: d.read_str().to_owned(),
contents: d.read_str().to_owned(),
},
_ => {
panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2");
panic!("invalid enum variant tag while decoding `TargetTuple`, expected 0..2");
}
}
}
}
impl TargetTriple {
/// Creates a target triple from the passed target triple string.
pub fn from_triple(triple: &str) -> Self {
TargetTriple::TargetTriple(triple.into())
impl TargetTuple {
/// Creates a target tuple from the passed target tuple string.
pub fn from_tuple(tuple: &str) -> Self {
TargetTuple::TargetTuple(tuple.into())
}
/// Creates a target triple from the passed target path.
/// Creates a target tuple from the passed target path.
pub fn from_path(path: &Path) -> Result<Self, io::Error> {
let canonicalized_path = try_canonicalize(path)?;
let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
@ -3843,46 +3843,47 @@ pub fn from_path(path: &Path) -> Result<Self, io::Error> {
format!("target path {canonicalized_path:?} is not a valid file: {err}"),
)
})?;
let triple = canonicalized_path
let tuple = canonicalized_path
.file_stem()
.expect("target path must not be empty")
.to_str()
.expect("target path must be valid unicode")
.to_owned();
Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents })
Ok(TargetTuple::TargetJson { path_for_rustdoc: canonicalized_path, tuple, contents })
}
/// Returns a string triple for this target.
/// Returns a string tuple for this target.
///
/// If this target is a path, the file name (without extension) is returned.
pub fn triple(&self) -> &str {
pub fn tuple(&self) -> &str {
match *self {
TargetTriple::TargetTriple(ref triple)
| TargetTriple::TargetJson { ref triple, .. } => triple,
TargetTuple::TargetTuple(ref tuple) | TargetTuple::TargetJson { ref tuple, .. } => {
tuple
}
}
}
/// Returns an extended string triple for this target.
/// Returns an extended string tuple for this target.
///
/// If this target is a path, a hash of the path is appended to the triple returned
/// by `triple()`.
pub fn debug_triple(&self) -> String {
/// If this target is a path, a hash of the path is appended to the tuple returned
/// by `tuple()`.
pub fn debug_tuple(&self) -> String {
use std::hash::DefaultHasher;
match self {
TargetTriple::TargetTriple(triple) => triple.to_owned(),
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => {
TargetTuple::TargetTuple(tuple) => tuple.to_owned(),
TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents: content } => {
let mut hasher = DefaultHasher::new();
content.hash(&mut hasher);
let hash = hasher.finish();
format!("{triple}-{hash}")
format!("{tuple}-{hash}")
}
}
}
}
impl fmt::Display for TargetTriple {
impl fmt::Display for TargetTuple {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.debug_triple())
write!(f, "{}", self.debug_tuple())
}
}

View File

@ -766,6 +766,67 @@ fn cmp_fn_sig(
values
}
pub fn cmp_traits(
&self,
def_id1: DefId,
args1: &[ty::GenericArg<'tcx>],
def_id2: DefId,
args2: &[ty::GenericArg<'tcx>],
) -> (DiagStyledString, DiagStyledString) {
let mut values = (DiagStyledString::new(), DiagStyledString::new());
if def_id1 != def_id2 {
values.0.push_highlighted(self.tcx.def_path_str(def_id1).as_str());
values.1.push_highlighted(self.tcx.def_path_str(def_id2).as_str());
} else {
values.0.push_normal(self.tcx.item_name(def_id1).as_str());
values.1.push_normal(self.tcx.item_name(def_id2).as_str());
}
if args1.len() != args2.len() {
let (pre, post) = if args1.len() > 0 { ("<", ">") } else { ("", "") };
values.0.push_normal(format!(
"{pre}{}{post}",
args1.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ")
));
let (pre, post) = if args2.len() > 0 { ("<", ">") } else { ("", "") };
values.1.push_normal(format!(
"{pre}{}{post}",
args2.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ")
));
return values;
}
if args1.len() > 0 {
values.0.push_normal("<");
values.1.push_normal("<");
}
for (i, (a, b)) in std::iter::zip(args1, args2).enumerate() {
let a_str = a.to_string();
let b_str = b.to_string();
if let (Some(a), Some(b)) = (a.as_type(), b.as_type()) {
let (a, b) = self.cmp(a, b);
values.0.0.extend(a.0);
values.1.0.extend(b.0);
} else if a_str != b_str {
values.0.push_highlighted(a_str);
values.1.push_highlighted(b_str);
} else {
values.0.push_normal(a_str);
values.1.push_normal(b_str);
}
if i + 1 < args1.len() {
values.0.push_normal(", ");
values.1.push_normal(", ");
}
}
if args1.len() > 0 {
values.0.push_normal(">");
values.1.push_normal(">");
}
values
}
/// Compares two given types, eliding parts that are the same between them and highlighting
/// relevant differences, and return two representation of those types for highlighted printing.
pub fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagStyledString, DiagStyledString) {

View File

@ -6,8 +6,8 @@
use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, StringPart, Suggestions, pluralize,
struct_span_code_err,
Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions,
pluralize, struct_span_code_err,
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@ -328,6 +328,11 @@ pub fn report_selection_error(
}
} else if let Some(custom_explanation) = safe_transmute_explanation {
err.span_label(span, custom_explanation);
} else if explanation.len() > self.tcx.sess.diagnostic_width() {
// Really long types don't look good as span labels, instead move it
// to a `help`.
err.span_label(span, "unsatisfied trait bound");
err.help(explanation);
} else {
err.span_label(span, explanation);
}
@ -1832,21 +1837,81 @@ pub(super) fn report_similar_impl_candidates(
if impl_trait_ref.references_error() {
return false;
}
let self_ty = impl_trait_ref.self_ty().to_string();
err.highlighted_help(vec![
StringPart::normal(format!(
"the trait `{}` ",
impl_trait_ref.print_trait_sugared()
)),
StringPart::highlighted("is"),
if let [child, ..] = &err.children[..]
&& child.level == Level::Help
&& let Some(line) = child.messages.get(0)
&& let Some(line) = line.0.as_str()
&& line.starts_with("the trait")
&& line.contains("is not implemented for")
{
// HACK(estebank): we remove the pre-existing
// "the trait `X` is not implemented for" note, which only happens if there
// was a custom label. We do this because we want that note to always be the
// first, and making this logic run earlier will get tricky. For now, we
// instead keep the logic the same and modify the already constructed error
// to avoid the wording duplication.
err.children.remove(0);
}
let traits = self.cmp_traits(
obligation_trait_ref.def_id,
&obligation_trait_ref.args[1..],
impl_trait_ref.def_id,
&impl_trait_ref.args[1..],
);
let traits_content = (traits.0.content(), traits.1.content());
let types = self.cmp(obligation_trait_ref.self_ty(), impl_trait_ref.self_ty());
let types_content = (types.0.content(), types.1.content());
let mut msg = vec![StringPart::normal("the trait `")];
if traits_content.0 == traits_content.1 {
msg.push(StringPart::normal(
impl_trait_ref.print_trait_sugared().to_string(),
));
} else {
msg.extend(traits.0.0);
}
msg.extend([
StringPart::normal("` "),
StringPart::highlighted("is not"),
StringPart::normal(" implemented for `"),
if let [TypeError::Sorts(_)] = &terrs[..] {
StringPart::normal(self_ty)
} else {
StringPart::highlighted(self_ty)
},
StringPart::normal("`"),
]);
if types_content.0 == types_content.1 {
let ty =
self.tcx.short_ty_string(obligation_trait_ref.self_ty(), &mut None);
msg.push(StringPart::normal(ty));
} else {
msg.extend(types.0.0);
}
msg.push(StringPart::normal("`"));
if types_content.0 == types_content.1 {
msg.push(StringPart::normal("\nbut trait `"));
msg.extend(traits.1.0);
msg.extend([
StringPart::normal("` "),
StringPart::highlighted("is"),
StringPart::normal(" implemented for it"),
]);
} else if traits_content.0 == traits_content.1 {
msg.extend([
StringPart::normal("\nbut it "),
StringPart::highlighted("is"),
StringPart::normal(" implemented for `"),
]);
msg.extend(types.1.0);
msg.push(StringPart::normal("`"));
} else {
msg.push(StringPart::normal("\nbut trait `"));
msg.extend(traits.1.0);
msg.extend([
StringPart::normal("` "),
StringPart::highlighted("is"),
StringPart::normal(" implemented for `"),
]);
msg.extend(types.1.0);
msg.push(StringPart::normal("`"));
}
err.highlighted_help(msg);
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
let exp_found = self.resolve_vars_if_possible(*exp_found);
@ -2475,12 +2540,16 @@ fn try_to_add_help_message(
&& self.tcx.trait_impls_of(trait_def_id).is_empty()
&& !self.tcx.trait_is_auto(trait_def_id)
&& !self.tcx.trait_is_alias(trait_def_id)
&& trait_predicate.polarity() == ty::PredicatePolarity::Positive
{
err.span_help(
self.tcx.def_span(trait_def_id),
crate::fluent_generated::trait_selection_trait_has_no_impls,
);
} else if !suggested && !unsatisfied_const {
} else if !suggested
&& !unsatisfied_const
&& trait_predicate.polarity() == ty::PredicatePolarity::Positive
{
// Can't show anything else useful, try to find similar impls.
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
if !self.report_similar_impl_candidates(

View File

@ -3563,17 +3563,34 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
)]);
}
ObligationCauseCode::OpaqueReturnType(expr_info) => {
if let Some((expr_ty, hir_id)) = expr_info {
let expr_ty = self.tcx.short_ty_string(expr_ty, long_ty_file);
let expr = self.infcx.tcx.hir().expect_expr(hir_id);
err.span_label(
expr.span,
with_forced_trimmed_paths!(format!(
"return type was inferred to be `{expr_ty}` here",
)),
);
suggest_remove_deref(err, &expr);
}
let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file);
let expr = tcx.hir().expect_expr(hir_id);
(expr_ty, expr)
} else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
&& let body = tcx.hir().body(body_id)
&& let hir::ExprKind::Block(block, _) = body.value.kind
&& let Some(expr) = block.expr
&& let Some(expr_ty) = self
.typeck_results
.as_ref()
.and_then(|typeck| typeck.node_type_opt(expr.hir_id))
&& let Some(pred) = predicate.as_clause()
&& let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
&& self.can_eq(param_env, pred.self_ty(), expr_ty)
{
let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file);
(expr_ty, expr)
} else {
return;
};
err.span_label(
expr.span,
with_forced_trimmed_paths!(format!(
"return type was inferred to be `{expr_ty}` here",
)),
);
suggest_remove_deref(err, &expr);
}
}
}
@ -3680,6 +3697,9 @@ pub fn suggest_derive(
err: &mut Diag<'_>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
if trait_pred.polarity() == ty::PredicatePolarity::Negative {
return;
}
let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
return;
};

View File

@ -136,7 +136,6 @@ impl<T, const N: usize> IntoIter<T, N> {
/// assert_eq!(r.collect::<Vec<_>>(), vec![10, 11, 12, 13, 14, 15]);
/// ```
#[unstable(feature = "array_into_iter_constructors", issue = "91583")]
#[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
pub const unsafe fn new_unchecked(
buffer: [MaybeUninit<T>; N],
initialized: Range<usize>,
@ -199,7 +198,6 @@ impl<T, const N: usize> IntoIter<T, N> {
/// assert_eq!(get_bytes(false).collect::<Vec<_>>(), vec![]);
/// ```
#[unstable(feature = "array_into_iter_constructors", issue = "91583")]
#[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
pub const fn empty() -> Self {
let buffer = [const { MaybeUninit::uninit() }; N];
let initialized = 0..0;

View File

@ -1515,7 +1515,6 @@ pub const fn is_ascii_digit(&self) -> bool {
/// ```
#[must_use]
#[unstable(feature = "is_ascii_octdigit", issue = "101288")]
#[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")]
#[inline]
pub const fn is_ascii_octdigit(&self) -> bool {
matches!(*self, '0'..='7')

View File

@ -112,11 +112,8 @@
#![feature(asm_experimental_arch)]
#![feature(const_align_of_val)]
#![feature(const_align_of_val_raw)]
#![feature(const_align_offset)]
#![feature(const_alloc_layout)]
#![feature(const_arguments_as_str)]
#![feature(const_array_into_iter_constructors)]
#![feature(const_bigint_helper_methods)]
#![feature(const_black_box)]
#![feature(const_char_encode_utf16)]
#![feature(const_eval_select)]
@ -125,17 +122,14 @@
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_nonnull_new)]
#![feature(const_num_midpoint)]
#![feature(const_option_ext)]
#![feature(const_pin_2)]
#![feature(const_pointer_is_aligned)]
#![feature(const_ptr_is_null)]
#![feature(const_ptr_sub_ptr)]
#![feature(const_raw_ptr_comparison)]
#![feature(const_size_of_val)]
#![feature(const_size_of_val_raw)]
#![feature(const_sockaddr_setters)]
#![feature(const_strict_overflow_ops)]
#![feature(const_swap)]
#![feature(const_try)]
#![feature(const_type_id)]
@ -167,7 +161,6 @@
#![feature(unchecked_neg)]
#![feature(unchecked_shifts)]
#![feature(utf16_extra)]
#![feature(utf16_extra_const)]
#![feature(variant_count)]
// tidy-alphabetical-end
//

View File

@ -338,7 +338,6 @@ pub const fn uninit() -> MaybeUninit<T> {
/// let data = read(&mut buf);
/// ```
#[unstable(feature = "maybe_uninit_uninit_array", issue = "96097")]
#[rustc_const_unstable(feature = "const_maybe_uninit_uninit_array", issue = "96097")]
#[must_use]
#[inline(always)]
pub const fn uninit_array<const N: usize>() -> [Self; N] {
@ -946,7 +945,6 @@ pub unsafe fn assume_init_drop(&mut self) {
/// assert_eq!(array, [0, 1, 2]);
/// ```
#[unstable(feature = "maybe_uninit_array_assume_init", issue = "96097")]
#[rustc_const_unstable(feature = "const_maybe_uninit_array_assume_init", issue = "96097")]
#[inline(always)]
#[track_caller]
pub const unsafe fn array_assume_init<const N: usize>(array: [Self; N]) -> [T; N] {
@ -973,7 +971,6 @@ pub unsafe fn assume_init_drop(&mut self) {
///
/// [`assume_init_ref`]: MaybeUninit::assume_init_ref
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
// SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that
@ -995,7 +992,6 @@ pub unsafe fn assume_init_drop(&mut self) {
///
/// [`assume_init_mut`]: MaybeUninit::assume_init_mut
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] {
// SAFETY: similar to safety notes for `slice_get_ref`, but we have a
@ -1005,7 +1001,6 @@ pub unsafe fn assume_init_drop(&mut self) {
/// Gets a pointer to the first element of the array.
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub const fn slice_as_ptr(this: &[MaybeUninit<T>]) -> *const T {
this.as_ptr() as *const T
@ -1013,7 +1008,6 @@ pub const fn slice_as_ptr(this: &[MaybeUninit<T>]) -> *const T {
/// Gets a mutable pointer to the first element of the array.
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit<T>]) -> *mut T {
this.as_mut_ptr() as *mut T

View File

@ -373,7 +373,6 @@ pub const fn is_documentation(&self) -> bool {
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
/// ```
#[unstable(feature = "ip", issue = "27709")]
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
#[must_use]
#[inline]
pub const fn is_benchmarking(&self) -> bool {

View File

@ -748,7 +748,6 @@ pub const fn is_sign_negative(self) -> bool {
/// [`MAX`]: Self::MAX
#[inline]
#[unstable(feature = "float_next_up_down", issue = "91399")]
#[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_up(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
@ -797,7 +796,6 @@ pub const fn next_up(self) -> Self {
/// [`MAX`]: Self::MAX
#[inline]
#[unstable(feature = "float_next_up_down", issue = "91399")]
#[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_down(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here

View File

@ -765,7 +765,6 @@ pub fn is_negative(self) -> bool {
/// [`MAX`]: Self::MAX
#[inline]
#[unstable(feature = "float_next_up_down", issue = "91399")]
#[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_up(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
@ -814,7 +813,6 @@ pub const fn next_up(self) -> Self {
/// [`MAX`]: Self::MAX
#[inline]
#[unstable(feature = "float_next_up_down", issue = "91399")]
#[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_down(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here

View File

@ -477,7 +477,6 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -573,7 +572,6 @@ pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -629,7 +627,6 @@ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -725,7 +722,6 @@ pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
#[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -781,7 +777,6 @@ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -895,7 +890,6 @@ pub const fn checked_div(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -969,7 +963,6 @@ pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1042,7 +1035,6 @@ pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1115,7 +1107,6 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1203,7 +1194,6 @@ pub const fn checked_neg(self) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")]
///
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1266,7 +1256,6 @@ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
#[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1325,7 +1314,6 @@ pub const fn strict_shl(self, rhs: u32) -> Self {
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
/// ```
#[unstable(feature = "unbounded_shifts", issue = "129375")]
#[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1391,7 +1379,6 @@ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
#[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1452,7 +1439,6 @@ pub const fn strict_shr(self, rhs: u32) -> Self {
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")]
/// ```
#[unstable(feature = "unbounded_shifts", issue = "129375")]
#[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1519,7 +1505,6 @@ pub const fn checked_abs(self) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1594,7 +1579,6 @@ pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -2368,7 +2352,6 @@ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
/// assert_eq!((sum1, sum0), (6, 8));
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -2476,7 +2459,6 @@ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
#[doc = concat!("assert_eq!((diff1, diff0), (10, ", stringify!($UnsignedT), "::MAX));")]
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]

View File

@ -114,7 +114,6 @@ macro_rules! midpoint_impl {
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")]
/// ```
#[unstable(feature = "num_midpoint", issue = "110840")]
#[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -142,7 +141,6 @@ pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
/// ```
#[unstable(feature = "num_midpoint", issue = "110840")]
#[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -170,7 +168,6 @@ pub const fn midpoint(self, rhs: Self) -> Self {
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")]
/// ```
#[unstable(feature = "num_midpoint", issue = "110840")]
#[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -196,7 +193,6 @@ pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
/// ```
#[unstable(feature = "num_midpoint", issue = "110840")]
#[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -229,7 +225,6 @@ macro_rules! widening_impl {
/// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2));
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -320,7 +315,6 @@ pub const fn widening_mul(self, rhs: Self) -> (Self, Self) {
/// );
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -915,7 +909,6 @@ pub const fn is_ascii_digit(&self) -> bool {
/// ```
#[must_use]
#[unstable(feature = "is_ascii_octdigit", issue = "101288")]
#[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")]
#[inline]
pub const fn is_ascii_octdigit(&self) -> bool {
matches!(*self, b'0'..=b'7')
@ -1195,7 +1188,6 @@ impl u16 {
/// ```
#[must_use]
#[unstable(feature = "utf16_extra", issue = "94919")]
#[rustc_const_unstable(feature = "utf16_extra_const", issue = "94919")]
#[inline]
pub const fn is_utf16_surrogate(self) -> bool {
matches!(self, 0xD800..=0xDFFF)

View File

@ -1474,7 +1474,6 @@ pub const fn ilog10(self) -> u32 {
/// # }
/// ```
#[unstable(feature = "num_midpoint", issue = "110840")]
#[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]

View File

@ -524,7 +524,6 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -626,7 +625,6 @@ pub const fn checked_add_signed(self, rhs: $SignedT) -> Option<Self> {
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_signed(3);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -691,7 +689,6 @@ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -873,7 +870,6 @@ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -975,7 +971,6 @@ pub const fn checked_div(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@ -1035,7 +1030,6 @@ pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@ -1097,7 +1091,6 @@ pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@ -1159,7 +1152,6 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
#[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@ -1392,7 +1384,6 @@ pub const fn checked_neg(self) -> Option<Self> {
#[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")]
///
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1455,7 +1446,6 @@ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
#[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1514,7 +1504,6 @@ pub const fn strict_shl(self, rhs: u32) -> Self {
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
/// ```
#[unstable(feature = "unbounded_shifts", issue = "129375")]
#[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1580,7 +1569,6 @@ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
#[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1639,7 +1627,6 @@ pub const fn strict_shr(self, rhs: u32) -> Self {
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")]
/// ```
#[unstable(feature = "unbounded_shifts", issue = "129375")]
#[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1714,7 +1701,6 @@ pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -2290,7 +2276,6 @@ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
/// assert_eq!((sum1, sum0), (9, 6));
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -2382,7 +2367,6 @@ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
#[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")]
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]

View File

@ -240,7 +240,6 @@ pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
///
/// The pointer can be later reconstructed with [`from_raw_parts`].
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata) {
(self.cast(), metadata(self))
@ -316,7 +315,6 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
/// ```
// FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized.
#[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
#[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
#[inline]
#[must_use]
pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T {
@ -1360,15 +1358,6 @@ pub unsafe fn read_volatile(self) -> T
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
/// the returned offset is correct in all terms other than alignment.
///
/// When this is called during compile-time evaluation (which is unstable), the implementation
/// may return `usize::MAX` in cases where that can never happen at runtime. This is because the
/// actual alignment of pointers is not known yet during compile-time, so an offset with
/// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8;
/// N]` might be allocated at an odd or an even address, but at compile-time this is not yet
/// known, so the execution has to be correct for either choice. It is therefore impossible to
/// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual
/// for unstable APIs.)
///
/// # Panics
///
/// The function panics if `align` is not a power-of-two.
@ -1397,8 +1386,7 @@ pub unsafe fn read_volatile(self) -> T
#[must_use]
#[inline]
#[stable(feature = "align_offset", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
pub const fn align_offset(self, align: usize) -> usize
pub fn align_offset(self, align: usize) -> usize
where
T: Sized,
{
@ -1433,94 +1421,10 @@ pub const fn align_offset(self, align: usize) -> usize
/// assert!(ptr.is_aligned());
/// assert!(!ptr.wrapping_byte_add(1).is_aligned());
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// is never aligned if cast to a type with a stricter alignment than the reference's
/// underlying allocation.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// const _: () = {
/// let data = AlignedI32(42);
/// let ptr = &data as *const AlignedI32;
/// assert!(ptr.is_aligned());
///
/// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned.
/// let ptr1 = ptr.cast::<AlignedI64>();
/// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
/// assert!(!ptr1.is_aligned());
/// assert!(!ptr2.is_aligned());
/// };
/// ```
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
/// const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.cast::<AlignedI64>().is_aligned(),
/// runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// const _: () = {
/// let ptr = 40 as *const AlignedI32;
/// assert!(ptr.is_aligned());
///
/// // For pointers with a known address, runtime and compiletime behavior are identical.
/// let ptr1 = ptr.cast::<AlignedI64>();
/// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
/// assert!(ptr1.is_aligned());
/// assert!(!ptr2.is_aligned());
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[must_use]
#[inline]
#[stable(feature = "pointer_is_aligned", since = "1.79.0")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned(self) -> bool
pub fn is_aligned(self) -> bool
where
T: Sized,
{
@ -1557,105 +1461,15 @@ pub const fn is_aligned(self) -> bool
///
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// cannot be stricter aligned than the reference's underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// const _: () = {
/// let data = AlignedI32(42);
/// let ptr = &data as *const AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
/// assert!(!ptr.is_aligned_to(8));
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
/// };
/// ```
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.is_aligned_to(8),
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
/// let ptr = 40 as *const u8;
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
/// assert!(ptr.is_aligned_to(8));
/// assert!(!ptr.is_aligned_to(16));
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[must_use]
#[inline]
#[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned_to(self, align: usize) -> bool {
pub fn is_aligned_to(self, align: usize) -> bool {
if !align.is_power_of_two() {
panic!("is_aligned_to: align is not a power-of-two");
}
#[inline]
fn runtime_impl(ptr: *const (), align: usize) -> bool {
ptr.addr() & (align - 1) == 0
}
#[inline]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
const fn const_impl(ptr: *const (), align: usize) -> bool {
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
ptr.align_offset(align) == 0
}
// The cast to `()` is used to
// 1. deal with fat pointers; and
// 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset.
const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl)
self.addr() & (align - 1) == 0
}
}
@ -1714,7 +1528,6 @@ pub const fn is_empty(self) -> bool {
/// ```
#[inline]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_ptr(self) -> *const T {
self as *const T
}
@ -1814,7 +1627,6 @@ pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
/// ```
#[inline]
#[unstable(feature = "array_ptr_get", issue = "119834")]
#[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
pub const fn as_ptr(self) -> *const T {
self as *const T
}
@ -1832,7 +1644,6 @@ pub const fn as_ptr(self) -> *const T {
/// ```
#[inline]
#[unstable(feature = "array_ptr_get", issue = "119834")]
#[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
pub const fn as_slice(self) -> *const [T] {
self
}

View File

@ -1852,9 +1852,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
///
/// Any questions go to @nagisa.
#[allow(ptr_to_integer_transmute_in_consts)]
#[lang = "align_offset"]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
// 1, where the method versions of these operations are not inlined.
use intrinsics::{
@ -1915,11 +1913,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
let stride = mem::size_of::<T>();
// SAFETY: This is just an inlined `p.addr()` (which is not
// a `const fn` so we cannot call it).
// During const eval, we hook this function to ensure that the pointer never
// has provenance, making this sound.
let addr: usize = unsafe { mem::transmute(p) };
let addr: usize = p.addr();
// SAFETY: `a` is a power-of-two, therefore non-zero.
let a_minus_one = unsafe { unchecked_sub(a, 1) };

View File

@ -1,6 +1,5 @@
use super::*;
use crate::cmp::Ordering::{Equal, Greater, Less};
use crate::intrinsics::const_eval_select;
use crate::mem::SizedTypeProperties;
use crate::slice::{self, SliceIndex};
@ -225,7 +224,6 @@ pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
///
/// The pointer can be later reconstructed with [`from_raw_parts_mut`].
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
(self.cast(), super::metadata(self))
@ -306,7 +304,6 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
/// ```
// FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized.
#[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
#[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
#[inline]
#[must_use]
pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T {
@ -659,7 +656,6 @@ pub fn mask(self, mask: usize) -> *mut T {
/// ```
// FIXME: mention it in the docs for `as_mut` and `as_uninit_mut` once stabilized.
#[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
#[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
#[inline]
#[must_use]
pub const unsafe fn as_mut_unchecked<'a>(self) -> &'a mut T {
@ -1639,8 +1635,7 @@ pub unsafe fn replace(self, src: T) -> T
#[must_use]
#[inline]
#[stable(feature = "align_offset", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
pub const fn align_offset(self, align: usize) -> usize
pub fn align_offset(self, align: usize) -> usize
where
T: Sized,
{
@ -1678,95 +1673,10 @@ pub const fn align_offset(self, align: usize) -> usize
/// assert!(ptr.is_aligned());
/// assert!(!ptr.wrapping_byte_add(1).is_aligned());
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// is never aligned if cast to a type with a stricter alignment than the reference's
/// underlying allocation.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// const _: () = {
/// let mut data = AlignedI32(42);
/// let ptr = &mut data as *mut AlignedI32;
/// assert!(ptr.is_aligned());
///
/// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned.
/// let ptr1 = ptr.cast::<AlignedI64>();
/// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
/// assert!(!ptr1.is_aligned());
/// assert!(!ptr2.is_aligned());
/// };
/// ```
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// // Also, note that mutable references are not allowed in the final value of constants.
/// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut();
/// const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.cast::<AlignedI64>().is_aligned(),
/// runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// const _: () = {
/// let ptr = 40 as *mut AlignedI32;
/// assert!(ptr.is_aligned());
///
/// // For pointers with a known address, runtime and compiletime behavior are identical.
/// let ptr1 = ptr.cast::<AlignedI64>();
/// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
/// assert!(ptr1.is_aligned());
/// assert!(!ptr2.is_aligned());
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[must_use]
#[inline]
#[stable(feature = "pointer_is_aligned", since = "1.79.0")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned(self) -> bool
pub fn is_aligned(self) -> bool
where
T: Sized,
{
@ -1803,106 +1713,15 @@ pub const fn is_aligned(self) -> bool
///
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// cannot be stricter aligned than the reference's underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// const _: () = {
/// let mut data = AlignedI32(42);
/// let ptr = &mut data as *mut AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
/// assert!(!ptr.is_aligned_to(8));
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
/// };
/// ```
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// // Also, note that mutable references are not allowed in the final value of constants.
/// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut();
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.is_aligned_to(8),
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
/// let ptr = 40 as *mut u8;
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
/// assert!(ptr.is_aligned_to(8));
/// assert!(!ptr.is_aligned_to(16));
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[must_use]
#[inline]
#[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned_to(self, align: usize) -> bool {
pub fn is_aligned_to(self, align: usize) -> bool {
if !align.is_power_of_two() {
panic!("is_aligned_to: align is not a power-of-two");
}
#[inline]
fn runtime_impl(ptr: *mut (), align: usize) -> bool {
ptr.addr() & (align - 1) == 0
}
#[inline]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
const fn const_impl(ptr: *mut (), align: usize) -> bool {
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
ptr.align_offset(align) == 0
}
// The cast to `()` is used to
// 1. deal with fat pointers; and
// 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset.
const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl)
self.addr() & (align - 1) == 0
}
}
@ -2059,7 +1878,6 @@ pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T]) {
/// ```
#[inline(always)]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_mut_ptr(self) -> *mut T {
self as *mut T
}
@ -2215,7 +2033,6 @@ pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
/// ```
#[inline]
#[unstable(feature = "array_ptr_get", issue = "119834")]
#[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
pub const fn as_mut_ptr(self) -> *mut T {
self as *mut T
}
@ -2236,7 +2053,6 @@ pub const fn as_mut_ptr(self) -> *mut T {
/// ```
#[inline]
#[unstable(feature = "array_ptr_get", issue = "119834")]
#[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")]
pub const fn as_mut_slice(self) -> *mut [T] {
self
}

View File

@ -131,7 +131,6 @@ pub const fn dangling() -> Self {
#[inline]
#[must_use]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
#[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
pub const unsafe fn as_uninit_ref<'a>(self) -> &'a MaybeUninit<T> {
// SAFETY: the caller must guarantee that `self` meets all the
// requirements for a reference.
@ -155,7 +154,6 @@ pub const fn dangling() -> Self {
#[inline]
#[must_use]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
#[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
pub const unsafe fn as_uninit_mut<'a>(self) -> &'a mut MaybeUninit<T> {
// SAFETY: the caller must guarantee that `self` meets all the
// requirements for a reference.
@ -230,7 +228,6 @@ pub const fn new(ptr: *mut T) -> Option<Self> {
/// Converts a reference to a `NonNull` pointer.
#[unstable(feature = "non_null_from_ref", issue = "130823")]
#[rustc_const_unstable(feature = "non_null_from_ref", issue = "130823")]
#[inline]
pub const fn from_ref(r: &T) -> Self {
// SAFETY: A reference cannot be null.
@ -239,7 +236,6 @@ pub const fn from_ref(r: &T) -> Self {
/// Converts a mutable reference to a `NonNull` pointer.
#[unstable(feature = "non_null_from_ref", issue = "130823")]
#[rustc_const_unstable(feature = "non_null_from_ref", issue = "130823")]
#[inline]
pub const fn from_mut(r: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null.
@ -253,7 +249,6 @@ pub const fn from_mut(r: &mut T) -> Self {
///
/// [`std::ptr::from_raw_parts`]: crate::ptr::from_raw_parts
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn from_raw_parts(
data_pointer: NonNull<()>,
@ -269,7 +264,6 @@ pub const fn from_raw_parts(
///
/// The pointer can be later reconstructed with [`NonNull::from_raw_parts`].
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@ -1198,8 +1192,7 @@ pub unsafe fn replace(self, src: T) -> T
#[inline]
#[must_use]
#[stable(feature = "non_null_convenience", since = "1.80.0")]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
pub const fn align_offset(self, align: usize) -> usize
pub fn align_offset(self, align: usize) -> usize
where
T: Sized,
{
@ -1230,98 +1223,10 @@ pub const fn align_offset(self, align: usize) -> usize
/// assert!(ptr.is_aligned());
/// assert!(!NonNull::new(ptr.as_ptr().wrapping_byte_add(1)).unwrap().is_aligned());
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// is never aligned if cast to a type with a stricter alignment than the reference's
/// underlying allocation.
///
/// ```
/// #![feature(const_nonnull_new)]
/// #![feature(const_pointer_is_aligned)]
/// use std::ptr::NonNull;
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// const _: () = {
/// let data = [AlignedI32(42), AlignedI32(42)];
/// let ptr = NonNull::<AlignedI32>::new(&data[0] as *const _ as *mut _).unwrap();
/// assert!(ptr.is_aligned());
///
/// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned.
/// let ptr1 = ptr.cast::<AlignedI64>();
/// let ptr2 = unsafe { ptr.add(1).cast::<AlignedI64>() };
/// assert!(!ptr1.is_aligned());
/// assert!(!ptr2.is_aligned());
/// };
/// ```
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
/// const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.cast::<AlignedI64>().is_aligned(),
/// runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_nonnull_new)]
/// use std::ptr::NonNull;
///
/// // On some platforms, the alignment of primitives is less than their size.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
/// #[repr(align(8))]
/// struct AlignedI64(i64);
///
/// const _: () = {
/// let ptr = NonNull::new(40 as *mut AlignedI32).unwrap();
/// assert!(ptr.is_aligned());
///
/// // For pointers with a known address, runtime and compiletime behavior are identical.
/// let ptr1 = ptr.cast::<AlignedI64>();
/// let ptr2 = NonNull::new(ptr.as_ptr().wrapping_add(1)).unwrap().cast::<AlignedI64>();
/// assert!(ptr1.is_aligned());
/// assert!(!ptr2.is_aligned());
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[inline]
#[must_use]
#[stable(feature = "pointer_is_aligned", since = "1.79.0")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned(self) -> bool
pub fn is_aligned(self) -> bool
where
T: Sized,
{
@ -1358,85 +1263,10 @@ pub const fn is_aligned(self) -> bool
///
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// cannot be stricter aligned than the reference's underlying allocation.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// const _: () = {
/// let data = AlignedI32(42);
/// let ptr = &data as *const AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
/// assert!(!ptr.is_aligned_to(8));
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
/// };
/// ```
///
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.is_aligned_to(8),
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned_to)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
/// let ptr = 40 as *const u8;
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
/// assert!(ptr.is_aligned_to(8));
/// assert!(!ptr.is_aligned_to(16));
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[inline]
#[must_use]
#[unstable(feature = "pointer_is_aligned_to", issue = "96284")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned_to(self, align: usize) -> bool {
pub fn is_aligned_to(self, align: usize) -> bool {
self.pointer.is_aligned_to(align)
}
}
@ -1545,7 +1375,6 @@ pub const fn as_non_null_ptr(self) -> NonNull<T> {
#[inline]
#[must_use]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_never_returns_null_ptr]
pub const fn as_mut_ptr(self) -> *mut T {
self.as_non_null_ptr().as_ptr()
@ -1591,7 +1420,6 @@ pub const fn as_mut_ptr(self) -> *mut T {
#[inline]
#[must_use]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
#[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
pub const unsafe fn as_uninit_slice<'a>(self) -> &'a [MaybeUninit<T>] {
// SAFETY: the caller must uphold the safety contract for `as_uninit_slice`.
unsafe { slice::from_raw_parts(self.cast().as_ptr(), self.len()) }
@ -1656,7 +1484,6 @@ pub const fn as_mut_ptr(self) -> *mut T {
#[inline]
#[must_use]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
#[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
pub const unsafe fn as_uninit_slice_mut<'a>(self) -> &'a mut [MaybeUninit<T>] {
// SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`.
unsafe { slice::from_raw_parts_mut(self.cast().as_ptr(), self.len()) }

View File

@ -3,6 +3,7 @@
use core::ascii::EscapeDefault;
use crate::fmt::{self, Write};
use crate::intrinsics::const_eval_select;
use crate::{ascii, iter, mem, ops};
#[cfg(not(test))]
@ -346,89 +347,93 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
/// If any of these loads produces something for which `contains_nonascii`
/// (above) returns true, then we know the answer is false.
#[inline]
#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion
#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails
#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior
const fn is_ascii(s: &[u8]) -> bool {
const USIZE_SIZE: usize = mem::size_of::<usize>();
// The runtime version behaves the same as the compiletime version, it's
// just more optimized.
return const_eval_select((s,), compiletime, runtime);
let len = s.len();
let align_offset = s.as_ptr().align_offset(USIZE_SIZE);
// If we wouldn't gain anything from the word-at-a-time implementation, fall
// back to a scalar loop.
//
// We also do this for architectures where `size_of::<usize>()` isn't
// sufficient alignment for `usize`, because it's a weird edge case.
if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
return is_ascii_simple(s);
const fn compiletime(s: &[u8]) -> bool {
is_ascii_simple(s)
}
// We always read the first word unaligned, which means `align_offset` is
// 0, we'd read the same value again for the aligned read.
let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset };
#[inline]
fn runtime(s: &[u8]) -> bool {
const USIZE_SIZE: usize = mem::size_of::<usize>();
let start = s.as_ptr();
// SAFETY: We verify `len < USIZE_SIZE` above.
let first_word = unsafe { (start as *const usize).read_unaligned() };
let len = s.len();
let align_offset = s.as_ptr().align_offset(USIZE_SIZE);
if contains_nonascii(first_word) {
return false;
}
// We checked this above, somewhat implicitly. Note that `offset_to_aligned`
// is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
// above.
debug_assert!(offset_to_aligned <= len);
// SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
// middle chunk of the slice.
let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize };
// `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
let mut byte_pos = offset_to_aligned;
// Paranoia check about alignment, since we're about to do a bunch of
// unaligned loads. In practice this should be impossible barring a bug in
// `align_offset` though.
// While this method is allowed to spuriously fail in CTFE, if it doesn't
// have alignment information it should have given a `usize::MAX` for
// `align_offset` earlier, sending things through the scalar path instead of
// this one, so this check should pass if it's reachable.
debug_assert!(word_ptr.is_aligned_to(mem::align_of::<usize>()));
// Read subsequent words until the last aligned word, excluding the last
// aligned word by itself to be done in tail check later, to ensure that
// tail is always one `usize` at most to extra branch `byte_pos == len`.
while byte_pos < len - USIZE_SIZE {
// Sanity check that the read is in bounds
debug_assert!(byte_pos + USIZE_SIZE <= len);
// And that our assumptions about `byte_pos` hold.
debug_assert!(matches!(
word_ptr.cast::<u8>().guaranteed_eq(start.wrapping_add(byte_pos)),
// These are from the same allocation, so will hopefully always be
// known to match even in CTFE, but if it refuses to compare them
// that's ok since it's just a debug check anyway.
None | Some(true),
));
// SAFETY: We know `word_ptr` is properly aligned (because of
// `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
let word = unsafe { word_ptr.read() };
if contains_nonascii(word) {
return false;
// If we wouldn't gain anything from the word-at-a-time implementation, fall
// back to a scalar loop.
//
// We also do this for architectures where `size_of::<usize>()` isn't
// sufficient alignment for `usize`, because it's a weird edge case.
if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
return is_ascii_simple(s);
}
byte_pos += USIZE_SIZE;
// SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
// after this `add`, `word_ptr` will be at most one-past-the-end.
word_ptr = unsafe { word_ptr.add(1) };
// We always read the first word unaligned, which means `align_offset` is
// 0, we'd read the same value again for the aligned read.
let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset };
let start = s.as_ptr();
// SAFETY: We verify `len < USIZE_SIZE` above.
let first_word = unsafe { (start as *const usize).read_unaligned() };
if contains_nonascii(first_word) {
return false;
}
// We checked this above, somewhat implicitly. Note that `offset_to_aligned`
// is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
// above.
debug_assert!(offset_to_aligned <= len);
// SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
// middle chunk of the slice.
let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize };
// `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
let mut byte_pos = offset_to_aligned;
// Paranoia check about alignment, since we're about to do a bunch of
// unaligned loads. In practice this should be impossible barring a bug in
// `align_offset` though.
// While this method is allowed to spuriously fail in CTFE, if it doesn't
// have alignment information it should have given a `usize::MAX` for
// `align_offset` earlier, sending things through the scalar path instead of
// this one, so this check should pass if it's reachable.
debug_assert!(word_ptr.is_aligned_to(mem::align_of::<usize>()));
// Read subsequent words until the last aligned word, excluding the last
// aligned word by itself to be done in tail check later, to ensure that
// tail is always one `usize` at most to extra branch `byte_pos == len`.
while byte_pos < len - USIZE_SIZE {
// Sanity check that the read is in bounds
debug_assert!(byte_pos + USIZE_SIZE <= len);
// And that our assumptions about `byte_pos` hold.
debug_assert!(word_ptr.cast::<u8>() == start.wrapping_add(byte_pos));
// SAFETY: We know `word_ptr` is properly aligned (because of
// `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
let word = unsafe { word_ptr.read() };
if contains_nonascii(word) {
return false;
}
byte_pos += USIZE_SIZE;
// SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
// after this `add`, `word_ptr` will be at most one-past-the-end.
word_ptr = unsafe { word_ptr.add(1) };
}
// Sanity check to ensure there really is only one `usize` left. This should
// be guaranteed by our loop condition.
debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE);
// SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() };
!contains_nonascii(last_word)
}
// Sanity check to ensure there really is only one `usize` left. This should
// be guaranteed by our loop condition.
debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE);
// SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() };
!contains_nonascii(last_word)
}

View File

@ -1,6 +1,7 @@
// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
use crate::intrinsics::const_eval_select;
use crate::mem;
const LO_USIZE: usize = usize::repeat_u8(0x01);
@ -50,58 +51,66 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
None
}
#[rustc_allow_const_fn_unstable(const_cmp)]
#[rustc_allow_const_fn_unstable(const_align_offset)]
#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//
// Split `text` in three parts
// - unaligned initial part, before the first word aligned address in text
// - body, scan by 2 words at a time
// - the last remaining part, < 2 word size
// The runtime version behaves the same as the compiletime version, it's
// just more optimized.
return const_eval_select((x, text), compiletime, runtime);
// search up to an aligned boundary
let len = text.len();
let ptr = text.as_ptr();
let mut offset = ptr.align_offset(USIZE_BYTES);
if offset > 0 {
// FIXME(const-hack, fee1-dead): replace with min
offset = if offset < len { offset } else { len };
// FIXME(const-hack, fee1-dead): replace with range slicing
// SAFETY: offset is within bounds
let slice = unsafe { super::from_raw_parts(text.as_ptr(), offset) };
if let Some(index) = memchr_naive(x, slice) {
return Some(index);
}
const fn compiletime(x: u8, text: &[u8]) -> Option<usize> {
memchr_naive(x, text)
}
// search the body of the text
let repeated_x = usize::repeat_u8(x);
while offset <= len - 2 * USIZE_BYTES {
// SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes
// between the offset and the end of the slice.
unsafe {
let u = *(ptr.add(offset) as *const usize);
let v = *(ptr.add(offset + USIZE_BYTES) as *const usize);
#[inline]
fn runtime(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//
// Split `text` in three parts
// - unaligned initial part, before the first word aligned address in text
// - body, scan by 2 words at a time
// - the last remaining part, < 2 word size
// break if there is a matching byte
let zu = contains_zero_byte(u ^ repeated_x);
let zv = contains_zero_byte(v ^ repeated_x);
if zu || zv {
break;
// search up to an aligned boundary
let len = text.len();
let ptr = text.as_ptr();
let mut offset = ptr.align_offset(USIZE_BYTES);
if offset > 0 {
offset = offset.min(len);
let slice = &text[..offset];
if let Some(index) = memchr_naive(x, slice) {
return Some(index);
}
}
offset += USIZE_BYTES * 2;
}
// Find the byte after the point the body loop stopped.
// FIXME(const-hack): Use `?` instead.
// FIXME(const-hack, fee1-dead): use range slicing
// SAFETY: offset is within bounds
let slice = unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) };
if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None }
// search the body of the text
let repeated_x = usize::repeat_u8(x);
while offset <= len - 2 * USIZE_BYTES {
// SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes
// between the offset and the end of the slice.
unsafe {
let u = *(ptr.add(offset) as *const usize);
let v = *(ptr.add(offset + USIZE_BYTES) as *const usize);
// break if there is a matching byte
let zu = contains_zero_byte(u ^ repeated_x);
let zv = contains_zero_byte(v ^ repeated_x);
if zu || zv {
break;
}
}
offset += USIZE_BYTES * 2;
}
// Find the byte after the point the body loop stopped.
// FIXME(const-hack): Use `?` instead.
// FIXME(const-hack, fee1-dead): use range slicing
let slice =
// SAFETY: offset is within bounds
unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) };
if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None }
}
}
/// Returns the last index matching the byte `x` in `text`.

View File

@ -82,7 +82,6 @@
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")]
#[rustc_allow_const_fn_unstable(str_internals)]
#[rustc_diagnostic_item = "str_from_utf8"]
pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
// FIXME(const-hack): This should use `?` again, once it's `const`
@ -218,7 +217,6 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
#[inline]
#[must_use]
#[unstable(feature = "str_from_raw_parts", issue = "119206")]
#[rustc_const_unstable(feature = "str_from_raw_parts", issue = "119206")]
pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str {
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
unsafe { &*ptr::from_raw_parts(ptr, len) }
@ -237,7 +235,6 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
#[inline]
#[must_use]
#[unstable(feature = "str_from_raw_parts", issue = "119206")]
#[rustc_const_unstable(feature = "const_str_from_raw_parts_mut", issue = "119206")]
pub const unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut str {
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe { &mut *ptr::from_raw_parts_mut(ptr, len) }

View File

@ -1,6 +1,7 @@
//! Operations related to UTF-8 validation.
use super::Utf8Error;
use crate::intrinsics::const_eval_select;
use crate::mem;
/// Returns the initial codepoint accumulator for the first byte.
@ -122,15 +123,28 @@ const fn contains_nonascii(x: usize) -> bool {
/// Walks through `v` checking that it's a valid UTF-8 sequence,
/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`.
#[inline(always)]
#[rustc_const_unstable(feature = "str_internals", issue = "none")]
#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior
pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
let mut index = 0;
let len = v.len();
let usize_bytes = mem::size_of::<usize>();
let ascii_block_size = 2 * usize_bytes;
const USIZE_BYTES: usize = mem::size_of::<usize>();
let ascii_block_size = 2 * USIZE_BYTES;
let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
let align = v.as_ptr().align_offset(usize_bytes);
let align = {
const fn compiletime(_v: &[u8]) -> usize {
usize::MAX
}
fn runtime(v: &[u8]) -> usize {
v.as_ptr().align_offset(USIZE_BYTES)
}
// Below, we safely fall back to a slower codepath if the offset is `usize::MAX`,
// so the end-to-end behavior is the same at compiletime and runtime.
const_eval_select((v,), compiletime, runtime)
};
while index < len {
let old_offset = index;
@ -209,11 +223,11 @@ macro_rules! next {
// Ascii case, try to skip forward quickly.
// When the pointer is aligned, read 2 words of data per iteration
// until we find a word containing a non-ascii byte.
if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 {
if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 {
let ptr = v.as_ptr();
while index < blocks_end {
// SAFETY: since `align - index` and `ascii_block_size` are
// multiples of `usize_bytes`, `block = ptr.add(index)` is
// multiples of `USIZE_BYTES`, `block = ptr.add(index)` is
// always aligned with a `usize` so it's safe to dereference
// both `block` and `block.add(1)`.
unsafe {

View File

@ -130,7 +130,6 @@ pub const fn get_mut(&mut self) -> &mut T {
/// access to the underlying value, but _pinned_ `Exclusive`s only
/// produce _pinned_ access to the underlying value.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
@ -154,7 +153,6 @@ pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive<T> {
/// a _pinned mutable_ reference to a `T`. This allows you to skip
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {

View File

@ -253,7 +253,6 @@ pub const fn waker(&self) -> &'a Waker {
/// Returns a reference to the [`LocalWaker`] for the current task.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const fn local_waker(&self) -> &'a LocalWaker {
&self.local_waker
}
@ -261,7 +260,6 @@ pub const fn local_waker(&self) -> &'a LocalWaker {
/// Returns a reference to the extension data for the current task.
#[inline]
#[unstable(feature = "context_ext", issue = "123392")]
#[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn ext(&mut self) -> &mut dyn Any {
// FIXME: this field makes Context extra-weird about unwind safety
// can we justify AssertUnwindSafe if we stabilize this? do we care?
@ -337,7 +335,6 @@ pub const fn from_waker(waker: &'a Waker) -> Self {
/// Creates a ContextBuilder from an existing Context.
#[inline]
#[unstable(feature = "context_ext", issue = "123392")]
#[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn from(cx: &'a mut Context<'_>) -> Self {
let ext = match &mut cx.ext.0 {
ExtData::Some(ext) => ExtData::Some(*ext),
@ -355,7 +352,6 @@ pub const fn from(cx: &'a mut Context<'_>) -> Self {
/// Sets the value for the waker on `Context`.
#[inline]
#[unstable(feature = "context_ext", issue = "123392")]
#[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn waker(self, waker: &'a Waker) -> Self {
Self { waker, ..self }
}
@ -363,7 +359,6 @@ pub const fn waker(self, waker: &'a Waker) -> Self {
/// Sets the value for the local waker on `Context`.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self {
Self { local_waker, ..self }
}
@ -371,7 +366,6 @@ pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self {
/// Sets the value for the extension data on `Context`.
#[inline]
#[unstable(feature = "context_ext", issue = "123392")]
#[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn ext(self, data: &'a mut dyn Any) -> Self {
Self { ext: ExtData::Some(data), ..self }
}
@ -834,7 +828,6 @@ pub fn will_wake(&self, other: &LocalWaker) -> bool {
#[inline]
#[must_use]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const unsafe fn from_raw(waker: RawWaker) -> LocalWaker {
Self { waker }
}

View File

@ -883,7 +883,6 @@ pub const fn as_secs_f32(&self) -> f32 {
#[unstable(feature = "duration_millis_float", issue = "122451")]
#[must_use]
#[inline]
#[rustc_const_unstable(feature = "duration_millis_float", issue = "122451")]
pub const fn as_millis_f64(&self) -> f64 {
(self.secs as f64) * (MILLIS_PER_SEC as f64)
+ (self.nanos.0 as f64) / (NANOS_PER_MILLI as f64)
@ -904,7 +903,6 @@ pub const fn as_millis_f64(&self) -> f64 {
#[unstable(feature = "duration_millis_float", issue = "122451")]
#[must_use]
#[inline]
#[rustc_const_unstable(feature = "duration_millis_float", issue = "122451")]
pub const fn as_millis_f32(&self) -> f32 {
(self.secs as f32) * (MILLIS_PER_SEC as f32)
+ (self.nanos.0 as f32) / (NANOS_PER_MILLI as f32)

View File

@ -120,7 +120,19 @@ const fn comptime() -> bool {
#[inline]
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
#[inline]
fn runtime(ptr: *const (), align: usize, is_zst: bool) -> bool {
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
}
#[inline]
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
const fn comptime(ptr: *const (), _align: usize, is_zst: bool) -> bool {
is_zst || !ptr.is_null()
}
// This is just for safety checks so we can const_eval_select.
const_eval_select((ptr, align, is_zst), comptime, runtime)
}
#[inline]

View File

@ -1,6 +1,5 @@
///! This file is generated by src/tools/unicode-table-generator; do not edit manually!
#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline(always)]
const fn bitset_search<
const N: usize,
@ -424,7 +423,6 @@ pub mod lowercase {
(5, 187), (6, 78), (7, 132),
];
#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
pub const fn lookup(c: char) -> bool {
super::bitset_search(
c as u32,
@ -549,7 +547,6 @@ pub mod uppercase {
(2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171),
];
#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
pub const fn lookup(c: char) -> bool {
super::bitset_search(
c as u32,

View File

@ -16,17 +16,13 @@
#![feature(cell_update)]
#![feature(clone_to_uninit)]
#![feature(const_align_of_val_raw)]
#![feature(const_align_offset)]
#![feature(const_bigint_helper_methods)]
#![feature(const_black_box)]
#![feature(const_eval_select)]
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_nonnull_new)]
#![feature(const_num_midpoint)]
#![feature(const_option_ext)]
#![feature(const_pin_2)]
#![feature(const_pointer_is_aligned)]
#![feature(const_three_way_compare)]
#![feature(const_trait_impl)]
#![feature(core_intrinsics)]

View File

@ -359,22 +359,6 @@ fn align_offset_zst() {
}
}
#[test]
fn align_offset_zst_const() {
const {
// For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
// all, because no amount of elements will align the pointer.
let mut p = 1;
while p < 1024 {
assert!(ptr::without_provenance::<()>(p).align_offset(p) == 0);
if p != 1 {
assert!(ptr::without_provenance::<()>(p + 1).align_offset(p) == !0);
}
p = (p + 1).next_power_of_two();
}
}
}
#[test]
fn align_offset_stride_one() {
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
@ -396,25 +380,6 @@ fn align_offset_stride_one() {
}
}
#[test]
fn align_offset_stride_one_const() {
const {
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
// number of bytes.
let mut align = 1;
while align < 1024 {
let mut ptr = 1;
while ptr < 2 * align {
let expected = ptr % align;
let offset = if expected == 0 { 0 } else { align - expected };
assert!(ptr::without_provenance::<u8>(ptr).align_offset(align) == offset);
ptr += 1;
}
align = (align + 1).next_power_of_two();
}
}
}
#[test]
fn align_offset_various_strides() {
unsafe fn test_stride<T>(ptr: *const T, align: usize) -> bool {
@ -495,192 +460,6 @@ struct A10(
assert!(!x);
}
#[test]
fn align_offset_various_strides_const() {
const unsafe fn test_stride<T>(ptr: *const T, numptr: usize, align: usize) {
let mut expected = usize::MAX;
// Naive but definitely correct way to find the *first* aligned element of stride::<T>.
let mut el = 0;
while el < align {
if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
expected = el;
break;
}
el += 1;
}
let got = ptr.align_offset(align);
assert!(got == expected);
}
const {
// For pointers of stride != 1, we verify the algorithm against the naivest possible
// implementation
let mut align = 1;
let limit = 32;
while align < limit {
let mut ptr = 1;
while ptr < 4 * align {
unsafe {
#[repr(packed)]
struct A3(#[allow(dead_code)] u16, #[allow(dead_code)] u8);
test_stride::<A3>(ptr::without_provenance::<A3>(ptr), ptr, align);
struct A4(#[allow(dead_code)] u32);
test_stride::<A4>(ptr::without_provenance::<A4>(ptr), ptr, align);
#[repr(packed)]
struct A5(#[allow(dead_code)] u32, #[allow(dead_code)] u8);
test_stride::<A5>(ptr::without_provenance::<A5>(ptr), ptr, align);
#[repr(packed)]
struct A6(#[allow(dead_code)] u32, #[allow(dead_code)] u16);
test_stride::<A6>(ptr::without_provenance::<A6>(ptr), ptr, align);
#[repr(packed)]
struct A7(
#[allow(dead_code)] u32,
#[allow(dead_code)] u16,
#[allow(dead_code)] u8,
);
test_stride::<A7>(ptr::without_provenance::<A7>(ptr), ptr, align);
#[repr(packed)]
struct A8(#[allow(dead_code)] u32, #[allow(dead_code)] u32);
test_stride::<A8>(ptr::without_provenance::<A8>(ptr), ptr, align);
#[repr(packed)]
struct A9(
#[allow(dead_code)] u32,
#[allow(dead_code)] u32,
#[allow(dead_code)] u8,
);
test_stride::<A9>(ptr::without_provenance::<A9>(ptr), ptr, align);
#[repr(packed)]
struct A10(
#[allow(dead_code)] u32,
#[allow(dead_code)] u32,
#[allow(dead_code)] u16,
);
test_stride::<A10>(ptr::without_provenance::<A10>(ptr), ptr, align);
test_stride::<u32>(ptr::without_provenance::<u32>(ptr), ptr, align);
test_stride::<u128>(ptr::without_provenance::<u128>(ptr), ptr, align);
}
ptr += 1;
}
align = (align + 1).next_power_of_two();
}
}
}
#[test]
fn align_offset_with_provenance_const() {
const {
// On some platforms (e.g. msp430-none-elf), the alignment of `i32` is less than 4.
#[repr(align(4))]
struct AlignedI32(i32);
let data = AlignedI32(42);
// `stride % align == 0` (usual case)
let ptr: *const i32 = &data.0;
assert!(ptr.align_offset(1) == 0);
assert!(ptr.align_offset(2) == 0);
assert!(ptr.align_offset(4) == 0);
assert!(ptr.align_offset(8) == usize::MAX);
assert!(ptr.wrapping_byte_add(1).align_offset(1) == 0);
assert!(ptr.wrapping_byte_add(1).align_offset(2) == usize::MAX);
assert!(ptr.wrapping_byte_add(2).align_offset(1) == 0);
assert!(ptr.wrapping_byte_add(2).align_offset(2) == 0);
assert!(ptr.wrapping_byte_add(2).align_offset(4) == usize::MAX);
assert!(ptr.wrapping_byte_add(3).align_offset(1) == 0);
assert!(ptr.wrapping_byte_add(3).align_offset(2) == usize::MAX);
assert!(ptr.wrapping_add(42).align_offset(4) == 0);
assert!(ptr.wrapping_add(42).align_offset(8) == usize::MAX);
let ptr1: *const i8 = ptr.cast();
assert!(ptr1.align_offset(1) == 0);
assert!(ptr1.align_offset(2) == 0);
assert!(ptr1.align_offset(4) == 0);
assert!(ptr1.align_offset(8) == usize::MAX);
assert!(ptr1.wrapping_byte_add(1).align_offset(1) == 0);
assert!(ptr1.wrapping_byte_add(1).align_offset(2) == 1);
assert!(ptr1.wrapping_byte_add(1).align_offset(4) == 3);
assert!(ptr1.wrapping_byte_add(1).align_offset(8) == usize::MAX);
assert!(ptr1.wrapping_byte_add(2).align_offset(1) == 0);
assert!(ptr1.wrapping_byte_add(2).align_offset(2) == 0);
assert!(ptr1.wrapping_byte_add(2).align_offset(4) == 2);
assert!(ptr1.wrapping_byte_add(2).align_offset(8) == usize::MAX);
assert!(ptr1.wrapping_byte_add(3).align_offset(1) == 0);
assert!(ptr1.wrapping_byte_add(3).align_offset(2) == 1);
assert!(ptr1.wrapping_byte_add(3).align_offset(4) == 1);
assert!(ptr1.wrapping_byte_add(3).align_offset(8) == usize::MAX);
let ptr2: *const i16 = ptr.cast();
assert!(ptr2.align_offset(1) == 0);
assert!(ptr2.align_offset(2) == 0);
assert!(ptr2.align_offset(4) == 0);
assert!(ptr2.align_offset(8) == usize::MAX);
assert!(ptr2.wrapping_byte_add(1).align_offset(1) == 0);
assert!(ptr2.wrapping_byte_add(1).align_offset(2) == usize::MAX);
assert!(ptr2.wrapping_byte_add(2).align_offset(1) == 0);
assert!(ptr2.wrapping_byte_add(2).align_offset(2) == 0);
assert!(ptr2.wrapping_byte_add(2).align_offset(4) == 1);
assert!(ptr2.wrapping_byte_add(2).align_offset(8) == usize::MAX);
assert!(ptr2.wrapping_byte_add(3).align_offset(1) == 0);
assert!(ptr2.wrapping_byte_add(3).align_offset(2) == usize::MAX);
let ptr3: *const i64 = ptr.cast();
assert!(ptr3.align_offset(1) == 0);
assert!(ptr3.align_offset(2) == 0);
assert!(ptr3.align_offset(4) == 0);
assert!(ptr3.align_offset(8) == usize::MAX);
assert!(ptr3.wrapping_byte_add(1).align_offset(1) == 0);
assert!(ptr3.wrapping_byte_add(1).align_offset(2) == usize::MAX);
// `stride % align != 0` (edge case)
let ptr4: *const [u8; 3] = ptr.cast();
assert!(ptr4.align_offset(1) == 0);
assert!(ptr4.align_offset(2) == 0);
assert!(ptr4.align_offset(4) == 0);
assert!(ptr4.align_offset(8) == usize::MAX);
assert!(ptr4.wrapping_byte_add(1).align_offset(1) == 0);
assert!(ptr4.wrapping_byte_add(1).align_offset(2) == 1);
assert!(ptr4.wrapping_byte_add(1).align_offset(4) == 1);
assert!(ptr4.wrapping_byte_add(1).align_offset(8) == usize::MAX);
assert!(ptr4.wrapping_byte_add(2).align_offset(1) == 0);
assert!(ptr4.wrapping_byte_add(2).align_offset(2) == 0);
assert!(ptr4.wrapping_byte_add(2).align_offset(4) == 2);
assert!(ptr4.wrapping_byte_add(2).align_offset(8) == usize::MAX);
assert!(ptr4.wrapping_byte_add(3).align_offset(1) == 0);
assert!(ptr4.wrapping_byte_add(3).align_offset(2) == 1);
assert!(ptr4.wrapping_byte_add(3).align_offset(4) == 3);
assert!(ptr4.wrapping_byte_add(3).align_offset(8) == usize::MAX);
let ptr5: *const [u8; 5] = ptr.cast();
assert!(ptr5.align_offset(1) == 0);
assert!(ptr5.align_offset(2) == 0);
assert!(ptr5.align_offset(4) == 0);
assert!(ptr5.align_offset(8) == usize::MAX);
assert!(ptr5.wrapping_byte_add(1).align_offset(1) == 0);
assert!(ptr5.wrapping_byte_add(1).align_offset(2) == 1);
assert!(ptr5.wrapping_byte_add(1).align_offset(4) == 3);
assert!(ptr5.wrapping_byte_add(1).align_offset(8) == usize::MAX);
assert!(ptr5.wrapping_byte_add(2).align_offset(1) == 0);
assert!(ptr5.wrapping_byte_add(2).align_offset(2) == 0);
assert!(ptr5.wrapping_byte_add(2).align_offset(4) == 2);
assert!(ptr5.wrapping_byte_add(2).align_offset(8) == usize::MAX);
assert!(ptr5.wrapping_byte_add(3).align_offset(1) == 0);
assert!(ptr5.wrapping_byte_add(3).align_offset(2) == 1);
assert!(ptr5.wrapping_byte_add(3).align_offset(4) == 1);
assert!(ptr5.wrapping_byte_add(3).align_offset(8) == usize::MAX);
}
}
#[test]
fn align_offset_issue_103361() {
#[cfg(target_pointer_width = "64")]
@ -693,23 +472,6 @@ fn align_offset_issue_103361() {
let _ = ptr::without_provenance::<HugeSize>(SIZE).align_offset(SIZE);
}
#[test]
fn align_offset_issue_103361_const() {
#[cfg(target_pointer_width = "64")]
const SIZE: usize = 1 << 47;
#[cfg(target_pointer_width = "32")]
const SIZE: usize = 1 << 30;
#[cfg(target_pointer_width = "16")]
const SIZE: usize = 1 << 13;
struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]);
const {
assert!(ptr::without_provenance::<HugeSize>(SIZE - 1).align_offset(SIZE) == SIZE - 1);
assert!(ptr::without_provenance::<HugeSize>(SIZE).align_offset(SIZE) == 0);
assert!(ptr::without_provenance::<HugeSize>(SIZE + 1).align_offset(SIZE) == 1);
}
}
#[test]
fn is_aligned() {
let data = 42;
@ -726,25 +488,6 @@ fn is_aligned() {
assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
}
#[test]
fn is_aligned_const() {
const {
let data = 42;
let ptr: *const i32 = &data;
assert!(ptr.is_aligned());
assert!(ptr.is_aligned_to(1));
assert!(ptr.is_aligned_to(2));
assert!(ptr.is_aligned_to(4));
assert!(ptr.wrapping_byte_add(2).is_aligned_to(1));
assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
// At comptime neither `ptr` nor `ptr+1` is aligned to 8.
assert!(!ptr.is_aligned_to(8));
assert!(!ptr.wrapping_add(1).is_aligned_to(8));
}
}
#[test]
fn offset_from() {
let mut a = [0; 5];

View File

@ -256,7 +256,8 @@ The valid types of print values are:
- `crate-name` — The name of the crate.
- `file-names` — The names of the files created by the `link` emit kind.
- `sysroot` — Path to the sysroot.
- `target-libdir` - Path to the target libdir.
- `target-libdir` — Path to the target libdir.
- `host-tuple` — The target-tuple string of the host compiler (e.g. `x86_64-unknown-linux-gnu`)
- `cfg` — List of cfg values. See [conditional compilation] for more
information about cfg values.
- `target-list` — List of known targets. The target may be selected with the
@ -286,7 +287,7 @@ The valid types of print values are:
exact format of this debugging output is not a stable guarantee, other than
that it will include the linker executable and the text of each command-line
argument passed to the linker.
- `deployment-target` - The currently selected [deployment target] (or minimum OS version)
- `deployment-target` The currently selected [deployment target] (or minimum OS version)
for the selected Apple platform target. This value can be used or passed along to other
components alongside a Rust build that need this information, such as C compilers.
This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable

View File

@ -52,7 +52,7 @@ rustdoc 1.17.0 (56124baa9 2017-04-24)
binary: rustdoc
commit-hash: hash
commit-date: date
host: host-triple
host: host-tuple
release: 1.17.0
LLVM version: 3.9
```

View File

@ -17,7 +17,7 @@
use rustc_session::{EarlyDiagCtxt, getopts};
use rustc_span::FileName;
use rustc_span::edition::Edition;
use rustc_target::spec::TargetTriple;
use rustc_target::spec::TargetTuple;
use crate::core::new_dcx;
use crate::externalfiles::ExternalHtml;
@ -96,7 +96,7 @@ pub(crate) struct Options {
/// Unstable (`-Z`) options strings to pass to the compiler.
pub(crate) unstable_opts_strs: Vec<String>,
/// The target used to compile the crate against.
pub(crate) target: TargetTriple,
pub(crate) target: TargetTuple,
/// Edition used when reading the crate. Defaults to "2015". Also used by default when
/// compiling doctests from the crate.
pub(crate) edition: Edition,

View File

@ -24,7 +24,7 @@
use rustc_span::FileName;
use rustc_span::edition::Edition;
use rustc_span::symbol::sym;
use rustc_target::spec::{Target, TargetTriple};
use rustc_target::spec::{Target, TargetTuple};
use tempfile::{Builder as TempFileBuilder, TempDir};
use tracing::debug;
@ -414,10 +414,10 @@ pub(crate) struct UnusedExterns {
unused_extern_names: Vec<String>,
}
fn add_exe_suffix(input: String, target: &TargetTriple) -> String {
fn add_exe_suffix(input: String, target: &TargetTuple) -> String {
let exe_suffix = match target {
TargetTriple::TargetTriple(_) => Target::expect_builtin(target).options.exe_suffix,
TargetTriple::TargetJson { contents, .. } => {
TargetTuple::TargetTuple(_) => Target::expect_builtin(target).options.exe_suffix,
TargetTuple::TargetJson { contents, .. } => {
Target::from_json(contents.parse().unwrap()).unwrap().0.options.exe_suffix
}
};
@ -513,8 +513,8 @@ fn run_test(
compiler.arg("--emit=metadata");
}
compiler.arg("--target").arg(match &rustdoc_options.target {
TargetTriple::TargetTriple(s) => s,
TargetTriple::TargetJson { path_for_rustdoc, .. } => {
TargetTuple::TargetTuple(s) => s,
TargetTuple::TargetJson { path_for_rustdoc, .. } => {
path_for_rustdoc.to_str().expect("target path must be valid unicode")
}
});

View File

@ -761,7 +761,7 @@ pub fn expected_output_path(
/// Absolute path to the directory where all output for all tests in the given
/// `relative_dir` group should reside. Example:
/// /path/to/build/host-triple/test/ui/relative/
/// /path/to/build/host-tuple/test/ui/relative/
/// This is created early when tests are collected to avoid race conditions.
pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf {
config.build_base.join(relative_dir)
@ -784,7 +784,7 @@ pub fn output_testname_unique(
/// Absolute path to the directory where all output for the given
/// test/revision should reside. Example:
/// /path/to/build/host-triple/test/ui/relative/testname.revision.mode/
/// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/
pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
output_relative_path(config, &testpaths.relative_dir)
.join(output_testname_unique(config, testpaths, revision))
@ -792,13 +792,13 @@ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<
/// Absolute path to the base filename used as output for the given
/// test/revision. Example:
/// /path/to/build/host-triple/test/ui/relative/testname.revision.mode/testname
/// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/testname
pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
}
/// Absolute path to the directory to use for incremental compilation. Example:
/// /path/to/build/host-triple/test/ui/relative/testname.mode/testname.inc
/// /path/to/build/host-tuple/test/ui/relative/testname.mode/testname.inc
pub fn incremental_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
output_base_name(config, testpaths, revision).with_extension("inc")
}

View File

@ -1825,7 +1825,7 @@ fn safe_revision(&self) -> Option<&str> {
/// Gets the absolute path to the directory where all output for the given
/// test/revision should reside.
/// E.g., `/path/to/build/host-triple/test/ui/relative/testname.revision.mode/`.
/// E.g., `/path/to/build/host-tuple/test/ui/relative/testname.revision.mode/`.
fn output_base_dir(&self) -> PathBuf {
output_base_dir(self.config, self.testpaths, self.safe_revision())
}

View File

@ -691,7 +691,7 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self {
clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
#[cfg(unix)]
native_lib: config.native_lib.as_ref().map(|lib_file_path| {
let target_triple = tcx.sess.opts.target_triple.triple();
let target_triple = tcx.sess.opts.target_triple.tuple();
// Check if host target == the session target.
if env!("TARGET") != target_triple {
panic!(

View File

@ -3,7 +3,7 @@
#[derive(Builder)]
pub struct Environment {
host_triple: String,
host_tuple: String,
python_binary: String,
/// The rustc checkout, where the compiler source is located.
checkout_dir: Utf8PathBuf,
@ -28,8 +28,8 @@ pub struct Environment {
}
impl Environment {
pub fn host_triple(&self) -> &str {
&self.host_triple
pub fn host_tuple(&self) -> &str {
&self.host_tuple
}
pub fn python_binary(&self) -> &str {
@ -45,7 +45,7 @@ pub fn build_root(&self) -> Utf8PathBuf {
}
pub fn build_artifacts(&self) -> Utf8PathBuf {
self.build_root().join("build").join(&self.host_triple)
self.build_root().join("build").join(&self.host_tuple)
}
pub fn artifact_dir(&self) -> Utf8PathBuf {

View File

@ -105,9 +105,9 @@ pub fn build(env: &Environment) -> Self {
env.checkout_path().join("x.py").as_str(),
"build",
"--target",
&env.host_triple(),
&env.host_tuple(),
"--host",
&env.host_triple(),
&env.host_tuple(),
"--stage",
"2",
"library/std",

View File

@ -127,7 +127,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
shared,
} => {
let env = EnvironmentBuilder::default()
.host_triple(target_triple)
.host_tuple(target_triple)
.python_binary(python)
.checkout_dir(checkout_dir.clone())
.host_llvm_dir(llvm_dir)
@ -148,7 +148,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
let checkout_dir = Utf8PathBuf::from("/checkout");
let env = EnvironmentBuilder::default()
.host_triple(target_triple)
.host_tuple(target_triple)
.python_binary("python3".to_string())
.checkout_dir(checkout_dir.clone())
.host_llvm_dir(Utf8PathBuf::from("/rustroot"))
@ -170,7 +170,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
let checkout_dir: Utf8PathBuf = std::env::current_dir()?.try_into()?;
let env = EnvironmentBuilder::default()
.host_triple(target_triple)
.host_tuple(target_triple)
.python_binary("python".to_string())
.checkout_dir(checkout_dir.clone())
.host_llvm_dir(checkout_dir.join("citools").join("clang-rust"))

View File

@ -22,7 +22,7 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
assert!(extracted_path.is_dir());
Ok(extracted_path)
};
let host_triple = env.host_triple();
let host_triple = env.host_tuple();
let version = find_dist_version(&dist_dir)?;
// Extract rustc, libstd, cargo and src archives to create the optimized sysroot
@ -87,7 +87,7 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
x_py.as_str(),
"test",
"--build",
env.host_triple(),
env.host_tuple(),
"--stage",
"0",
"tests/assembly",

View File

@ -1,4 +1,3 @@
#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline(always)]
const fn bitset_search<
const N: usize,

View File

@ -97,11 +97,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.blank_line();
writeln!(
&mut self.file,
r#"#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]"#
)
.unwrap();
writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap();
if first_code_point > 0x7f {
writeln!(&mut self.file, " (c as u32) >= {first_code_point:#04x} &&").unwrap();

View File

@ -2,8 +2,9 @@ error[E0277]: the trait bound `NotClonableUpvar: Clone` is not satisfied in `{as
--> $DIR/not-clone-closure.rs:32:15
|
LL | not_clone.clone();
| ^^^^^ within `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}`, the trait `Clone` is not implemented for `NotClonableUpvar`
| ^^^^^ unsatisfied trait bound
|
= help: within `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}`, the trait `Clone` is not implemented for `NotClonableUpvar`
note: required because it's used within this closure
--> $DIR/not-clone-closure.rs:29:21
|

View File

@ -3,6 +3,9 @@ error[E0277]: `()` is not a future
|
LL | fn get_future() -> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
LL |
LL | panic!()
| -------- return type was inferred to be `_` here
|
= help: the trait `Future` is not implemented for `()`

View File

@ -1,4 +1,5 @@
//@ edition:2018
//@compile-flags: --diagnostic-width=300
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::future::Future;

View File

@ -1,5 +1,5 @@
error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied
--> $DIR/coroutine-not-future.rs:35:21
--> $DIR/coroutine-not-future.rs:36:21
|
LL | takes_coroutine(async_fn());
| --------------- ^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>`
@ -7,13 +7,13 @@ LL | takes_coroutine(async_fn());
| required by a bound introduced by this call
|
note: required by a bound in `takes_coroutine`
--> $DIR/coroutine-not-future.rs:19:39
--> $DIR/coroutine-not-future.rs:20:39
|
LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied
--> $DIR/coroutine-not-future.rs:37:21
--> $DIR/coroutine-not-future.rs:38:21
|
LL | takes_coroutine(returns_async_block());
| --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>`
@ -21,27 +21,27 @@ LL | takes_coroutine(returns_async_block());
| required by a bound introduced by this call
|
note: required by a bound in `takes_coroutine`
--> $DIR/coroutine-not-future.rs:19:39
--> $DIR/coroutine-not-future.rs:20:39
|
LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:39:21: 39:26}: Coroutine<_>` is not satisfied
--> $DIR/coroutine-not-future.rs:39:21
error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:40:21: 40:26}: Coroutine<_>` is not satisfied
--> $DIR/coroutine-not-future.rs:40:21
|
LL | takes_coroutine(async {});
| --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:39:21: 39:26}`
| --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:40:21: 40:26}`
| |
| required by a bound introduced by this call
|
note: required by a bound in `takes_coroutine`
--> $DIR/coroutine-not-future.rs:19:39
--> $DIR/coroutine-not-future.rs:20:39
|
LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
error[E0277]: `impl Coroutine<Yield = (), Return = ()>` is not a future
--> $DIR/coroutine-not-future.rs:43:18
--> $DIR/coroutine-not-future.rs:44:18
|
LL | takes_future(returns_coroutine());
| ------------ ^^^^^^^^^^^^^^^^^^^ `impl Coroutine<Yield = (), Return = ()>` is not a future
@ -50,13 +50,13 @@ LL | takes_future(returns_coroutine());
|
= help: the trait `Future` is not implemented for `impl Coroutine<Yield = (), Return = ()>`
note: required by a bound in `takes_future`
--> $DIR/coroutine-not-future.rs:18:26
--> $DIR/coroutine-not-future.rs:19:26
|
LL | fn takes_future(_f: impl Future<Output = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future
--> $DIR/coroutine-not-future.rs:47:9
error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:48:9: 48:14}` is not a future
--> $DIR/coroutine-not-future.rs:48:9
|
LL | takes_future(
| ------------ required by a bound introduced by this call
@ -65,11 +65,11 @@ LL | / |ctx| {
LL | |
LL | | ctx = yield ();
LL | | },
| |_________^ `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future
| |_________^ `{coroutine@$DIR/coroutine-not-future.rs:48:9: 48:14}` is not a future
|
= help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}`
= help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:48:9: 48:14}`
note: required by a bound in `takes_future`
--> $DIR/coroutine-not-future.rs:18:26
--> $DIR/coroutine-not-future.rs:19:26
|
LL | fn takes_future(_f: impl Future<Output = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`

View File

@ -20,10 +20,11 @@ error[E0277]: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as
--> $DIR/const_param_ty_bad.rs:8:11
|
LL | check(|| {});
| ----- ^^^^^ the trait `UnsizedConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}`
| ----- ^^^^^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
= help: the trait `UnsizedConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}`
note: required by a bound in `check`
--> $DIR/const_param_ty_bad.rs:4:18
|

View File

@ -4,7 +4,8 @@ error[E0277]: the trait bound `u16: Bar<N>` is not satisfied
LL | type Assoc = u16;
| ^^^ the trait `Bar<N>` is not implemented for `u16`
|
= help: the trait `Bar<3>` is implemented for `u16`
= help: the trait `Bar<N>` is not implemented for `u16`
but trait `Bar<3>` is implemented for it
note: required by a bound in `Foo::Assoc`
--> $DIR/associated-type-bound-fail.rs:4:17
|

View File

@ -18,7 +18,8 @@ LL |
LL | 1_u32
| ----- return type was inferred to be `u32` here
|
= help: the trait `Traitor<N, 2>` is implemented for `u32`
= help: the trait `Traitor<N, N>` is not implemented for `u32`
but trait `Traitor<N, 2>` is implemented for it
error[E0277]: the trait bound `u64: Traitor` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:21:13
@ -29,7 +30,8 @@ LL |
LL | 1_u64
| ----- return type was inferred to be `u64` here
|
= help: the trait `Traitor<1, 2>` is implemented for `u64`
= help: the trait `Traitor<1, 1>` is not implemented for `u64`
but trait `Traitor<1, 2>` is implemented for it
error[E0284]: type annotations needed
--> $DIR/rp_impl_trait_fail.rs:28:5

View File

@ -4,7 +4,8 @@ error[E0277]: the trait bound `u32: Trait` is not satisfied
LL | foo(&10_u32);
| ^^^^^^^ the trait `Trait` is not implemented for `u32`
|
= help: the trait `Trait<2>` is implemented for `u32`
= help: the trait `Trait<12>` is not implemented for `u32`
but trait `Trait<2>` is implemented for it
= note: required for the cast from `&u32` to `&dyn Trait`
error[E0277]: the trait bound `bool: Traitor<_>` is not satisfied
@ -13,7 +14,8 @@ error[E0277]: the trait bound `bool: Traitor<_>` is not satisfied
LL | bar(&true);
| ^^^^^ the trait `Traitor<_>` is not implemented for `bool`
|
= help: the trait `Traitor<2, 3>` is implemented for `bool`
= help: the trait `Traitor<_, _>` is not implemented for `bool`
but trait `Traitor<2, 3>` is implemented for it
= note: required for the cast from `&bool` to `&dyn Traitor<_>`
error: aborting due to 2 previous errors

View File

@ -10,7 +10,8 @@ error[E0277]: the trait bound `(): Trait<2>` is not satisfied
LL | (): Trait<N>;
| ^^^^^^^^ the trait `Trait<2>` is not implemented for `()`
|
= help: the trait `Trait<3>` is implemented for `()`
= help: the trait `Trait<2>` is not implemented for `()`
but trait `Trait<3>` is implemented for it
error[E0277]: the trait bound `(): Trait<1>` is not satisfied
--> $DIR/wfness.rs:18:13
@ -18,7 +19,8 @@ error[E0277]: the trait bound `(): Trait<1>` is not satisfied
LL | fn foo() -> DependentDefaultWfness {
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1>` is not implemented for `()`
|
= help: the trait `Trait<3>` is implemented for `()`
= help: the trait `Trait<1>` is not implemented for `()`
but trait `Trait<3>` is implemented for it
note: required by a bound in `WhereClause`
--> $DIR/wfness.rs:8:9
|

View File

@ -4,7 +4,8 @@ error[E0277]: the trait bound `A<_>: Bar<_>` is not satisfied
LL | let _ = A;
| ^ the trait `Bar<_>` is not implemented for `A<_>`
|
= help: the trait `Bar<_>` is implemented for `A<{ 6 + 1 }>`
= help: the trait `Bar<_>` is not implemented for `A<_>`
but it is implemented for `A<{ 6 + 1 }>`
note: required by a bound in `A`
--> $DIR/unused-substs-1.rs:9:11
|

View File

@ -5,7 +5,10 @@ LL | fn foo() -> impl Coroutine<u8> {
| ^^^^^^^^^^^^^^^^^^ expected due to this
...
LL | |_: ()| {}
| ------- found signature defined here
| ----------
| |
| found signature defined here
| return type was inferred to be `{coroutine@$DIR/arg-count-mismatch-on-unit-input.rs:8:5: 8:12}` here
|
= note: expected coroutine signature `fn(u8) -> _`
found coroutine signature `fn(()) -> _`

View File

@ -1,6 +1,7 @@
// gate-test-coroutine_clone
// Verifies that non-static coroutines can be cloned/copied if all their upvars and locals held
// across awaits can be cloned/copied.
//@compile-flags: --diagnostic-width=300
#![feature(coroutines, coroutine_clone, stmt_expr_attributes)]

View File

@ -1,76 +1,76 @@
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
--> $DIR/clone-impl.rs:49:5
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
--> $DIR/clone-impl.rs:50:5
|
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
| ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
...
LL | check_copy(&gen_clone_0);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<u32>`
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec<u32>`
|
note: captured value does not implement `Copy`
--> $DIR/clone-impl.rs:47:14
--> $DIR/clone-impl.rs:48:14
|
LL | drop(clonable_0);
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:89:18
--> $DIR/clone-impl.rs:90:18
|
LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
--> $DIR/clone-impl.rs:49:5
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
--> $DIR/clone-impl.rs:50:5
|
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
| ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
...
LL | check_copy(&gen_clone_0);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<char>`
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec<char>`
|
note: coroutine does not implement `Copy` as this value is used across a yield
--> $DIR/clone-impl.rs:45:9
--> $DIR/clone-impl.rs:46:9
|
LL | let v = vec!['a'];
| - has type `Vec<char>` which does not implement `Copy`
LL | yield;
| ^^^^^ yield occurs here, with `v` maybe used later
note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:89:18
--> $DIR/clone-impl.rs:90:18
|
LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
--> $DIR/clone-impl.rs:70:5
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
--> $DIR/clone-impl.rs:71:5
|
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
| ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
...
LL | check_copy(&gen_clone_1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<u32>`
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec<u32>`
|
note: captured value does not implement `Copy`
--> $DIR/clone-impl.rs:68:14
--> $DIR/clone-impl.rs:69:14
|
LL | drop(clonable_1);
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:89:18
--> $DIR/clone-impl.rs:90:18
|
LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
--> $DIR/clone-impl.rs:70:5
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
--> $DIR/clone-impl.rs:71:5
|
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
| ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
...
LL | check_copy(&gen_clone_1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<char>`
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec<char>`
|
note: coroutine does not implement `Copy` as this value is used across a yield
--> $DIR/clone-impl.rs:64:9
--> $DIR/clone-impl.rs:65:9
|
LL | let v = vec!['a'];
| - has type `Vec<char>` which does not implement `Copy`
@ -78,27 +78,27 @@ LL | let v = vec!['a'];
LL | yield;
| ^^^^^ yield occurs here, with `v` maybe used later
note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:89:18
--> $DIR/clone-impl.rs:90:18
|
LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
--> $DIR/clone-impl.rs:83:5
error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
--> $DIR/clone-impl.rs:84:5
|
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
| ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
...
LL | check_copy(&gen_non_clone);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Copy` is not implemented for `NonClone`
|
note: captured value does not implement `Copy`
--> $DIR/clone-impl.rs:81:14
--> $DIR/clone-impl.rs:82:14
|
LL | drop(non_clonable);
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy`
note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:89:18
--> $DIR/clone-impl.rs:90:18
|
LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy`
@ -108,22 +108,22 @@ LL + #[derive(Copy)]
LL | struct NonClone;
|
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
--> $DIR/clone-impl.rs:85:5
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
--> $DIR/clone-impl.rs:86:5
|
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
| ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
...
LL | check_clone(&gen_non_clone);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Clone` is not implemented for `NonClone`
|
note: captured value does not implement `Clone`
--> $DIR/clone-impl.rs:81:14
--> $DIR/clone-impl.rs:82:14
|
LL | drop(non_clonable);
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone`
note: required by a bound in `check_clone`
--> $DIR/clone-impl.rs:90:19
--> $DIR/clone-impl.rs:91:19
|
LL | fn check_clone<T: Clone>(_x: &T) {}
| ^^^^^ required by this bound in `check_clone`

View File

@ -3,18 +3,24 @@ error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}: C
|
LL | fn foo() -> impl Coroutine<Yield = u32, Return = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}`
LL | gen { yield 42 }
| ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}` here
error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}: Coroutine` is not satisfied
--> $DIR/gen_block_is_coro.rs:10:13
|
LL | fn bar() -> impl Coroutine<Yield = i64, Return = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}`
LL | gen { yield 42 }
| ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}` here
error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}: Coroutine` is not satisfied
--> $DIR/gen_block_is_coro.rs:14:13
|
LL | fn baz() -> impl Coroutine<Yield = i32, Return = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}`
LL | gen { yield 42 }
| ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}` here
error: aborting due to 3 previous errors

View File

@ -3,6 +3,8 @@ error[E0277]: `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:8}` is not a fut
|
LL | fn foo() -> impl std::future::Future {
| ^^^^^^^^^^^^^^^^^^^^^^^^ `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:8}` is not a future
LL | gen { yield 42 }
| ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:8}` here
|
= help: the trait `Future` is not implemented for `{gen block@$DIR/gen_block_is_no_future.rs:5:5: 5:8}`

View File

@ -1,3 +1,4 @@
//@compile-flags: --diagnostic-width=300
#![feature(coroutines)]
#![feature(coroutine_clone)]
#![feature(coroutine_trait)]

View File

@ -1,8 +1,8 @@
error[E0382]: borrow of moved value: `g`
--> $DIR/issue-105084.rs:38:14
--> $DIR/issue-105084.rs:39:14
|
LL | let mut g = #[coroutine]
| ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, which does not implement the `Copy` trait
| ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, which does not implement the `Copy` trait
...
LL | let mut h = copy(g);
| - value moved here
@ -11,7 +11,7 @@ LL | Pin::new(&mut g).resume(());
| ^^^^^^ value borrowed here after move
|
note: consider changing this parameter type in function `copy` to borrow instead if owning the value isn't necessary
--> $DIR/issue-105084.rs:9:21
--> $DIR/issue-105084.rs:10:21
|
LL | fn copy<T: Copy>(x: T) -> T {
| ---- ^ this parameter takes ownership of the value
@ -22,17 +22,17 @@ help: consider cloning the value if the performance cost is acceptable
LL | let mut h = copy(g.clone());
| ++++++++
error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`
--> $DIR/issue-105084.rs:32:17
error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
--> $DIR/issue-105084.rs:33:17
|
LL | || {
| -- within this `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`
| -- within this `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
...
LL | let mut h = copy(g);
| ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`
| ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`
|
note: coroutine does not implement `Copy` as this value is used across a yield
--> $DIR/issue-105084.rs:22:22
--> $DIR/issue-105084.rs:23:22
|
LL | Box::new((5, yield));
| -------------^^^^^--
@ -40,7 +40,7 @@ LL | Box::new((5, yield));
| | yield occurs here, with `Box::new((5, yield))` maybe used later
| has type `Box<(i32, ())>` which does not implement `Copy`
note: required by a bound in `copy`
--> $DIR/issue-105084.rs:9:12
--> $DIR/issue-105084.rs:10:12
|
LL | fn copy<T: Copy>(x: T) -> T {
| ^^^^ required by this bound in `copy`

View File

@ -14,6 +14,7 @@ fn foo(bar: bool) -> impl Coroutine<(bool,)> {
#[coroutine]
|bar| {
//~^ NOTE: found signature defined here
//~| NOTE: return type was inferred to be
if bar {
yield bar;
}

View File

@ -1,11 +1,21 @@
error[E0631]: type mismatch in coroutine arguments
--> $DIR/issue-88653.rs:8:22
|
LL | fn foo(bar: bool) -> impl Coroutine<(bool,)> {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected due to this
LL | fn foo(bar: bool) -> impl Coroutine<(bool,)> {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected due to this
...
LL | |bar| {
| ----- found signature defined here
LL | |bar| {
| -----
| |
| _____found signature defined here
| |
LL | |
LL | |
LL | | if bar {
LL | | yield bar;
LL | | }
LL | | }
| |_____- return type was inferred to be `{coroutine@$DIR/issue-88653.rs:15:5: 15:10}` here
|
= note: expected coroutine signature `fn((bool,)) -> _`
found coroutine signature `fn(bool) -> _`

View File

@ -1,15 +1,15 @@
error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` cannot be unpinned
--> $DIR/static-not-unpin.rs:18:18
error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:16:5: 16:14}` cannot be unpinned
--> $DIR/static-not-unpin.rs:19:18
|
LL | assert_unpin(coroutine);
| ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}`
| ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:16:5: 16:14}`
| |
| required by a bound introduced by this call
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required by a bound in `assert_unpin`
--> $DIR/static-not-unpin.rs:11:20
--> $DIR/static-not-unpin.rs:12:20
|
LL | fn assert_unpin<T: Unpin>(_: T) {}
| ^^^^^ required by this bound in `assert_unpin`

View File

@ -1,15 +1,15 @@
error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` cannot be unpinned
--> $DIR/static-not-unpin.rs:18:18
error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:16:5: 16:14}` cannot be unpinned
--> $DIR/static-not-unpin.rs:19:18
|
LL | assert_unpin(coroutine);
| ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}`
| ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:16:5: 16:14}`
| |
| required by a bound introduced by this call
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required by a bound in `assert_unpin`
--> $DIR/static-not-unpin.rs:11:20
--> $DIR/static-not-unpin.rs:12:20
|
LL | fn assert_unpin<T: Unpin>(_: T) {}
| ^^^^^ required by this bound in `assert_unpin`

View File

@ -1,6 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@[next] compile-flags: -Znext-solver --diagnostic-width=300
//@[current] compile-flags: --diagnostic-width=300
#![feature(coroutines, stmt_expr_attributes)]

View File

@ -4,7 +4,8 @@ error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
LL | SelectInt.check("bar");
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
|
= help: the trait `AsExpression<Text>` is implemented for `&str`
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
but trait `AsExpression<Text>` is implemented for it
= help: for that trait implementation, expected `Text`, found `Integer`
error: aborting due to 1 previous error

View File

@ -22,7 +22,8 @@ error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
LL | SelectInt.check("bar");
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
|
= help: the trait `AsExpression<Text>` is implemented for `&str`
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
but trait `AsExpression<Text>` is implemented for it
= help: for that trait implementation, expected `Text`, found `Integer`
error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`

View File

@ -16,7 +16,8 @@ error[E0277]: the trait bound `Infallible: From<()>` is not satisfied
LL | let () = K::<()>;
| ^^ the trait `From<()>` is not implemented for `Infallible`
|
= help: the trait `From<!>` is implemented for `Infallible`
= help: the trait `From<()>` is not implemented for `Infallible`
but trait `From<!>` is implemented for it
= help: for that trait implementation, expected `!`, found `()`
note: required by a bound in `K`
--> $DIR/unsatisfied-bounds.rs:12:17
@ -48,7 +49,8 @@ error[E0277]: the trait bound `Infallible: From<()>` is not satisfied
LL | let _ = <() as Trait<&'static str>>::B::<()>;
| ^^ the trait `From<()>` is not implemented for `Infallible`
|
= help: the trait `From<!>` is implemented for `Infallible`
= help: the trait `From<()>` is not implemented for `Infallible`
but trait `From<!>` is implemented for it
= help: for that trait implementation, expected `!`, found `()`
note: required by a bound in `Trait::B`
--> $DIR/unsatisfied-bounds.rs:21:21

View File

@ -1,4 +1,4 @@
<svg width="1104px" height="344px" xmlns="http://www.w3.org/2000/svg">
<svg width="1104px" height="398px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
@ -31,31 +31,37 @@
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">the trait `Bar&lt;i32&gt;` is not implemented for `Struct`</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
<tspan x="10px" y="118px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Struct</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Bar&lt;()&gt;` </tspan><tspan class="fg-magenta bold">is</tspan><tspan> implemented for `Struct`</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">------</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">return type was inferred to be `Struct` here</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: for that trait implementation, expected `</tspan><tspan class="fg-magenta bold">()</tspan><tspan>`, found `</tspan><tspan class="fg-magenta bold">i32</tspan><tspan>`</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required for `Struct` to implement `Foo&lt;i32&gt;`</tspan>
<tspan x="10px" y="172px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Bar&lt;</tspan><tspan class="fg-magenta bold">i32</tspan><tspan>&gt;` </tspan><tspan class="fg-magenta bold">is not</tspan><tspan> implemented for `Struct`</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:11:12</tspan>
<tspan x="10px" y="190px"><tspan> but trait `Bar&lt;</tspan><tspan class="fg-magenta bold">()</tspan><tspan>&gt;` </tspan><tspan class="fg-magenta bold">is</tspan><tspan> implemented for it</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
<tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: for that trait implementation, expected `</tspan><tspan class="fg-magenta bold">()</tspan><tspan>`, found `</tspan><tspan class="fg-magenta bold">i32</tspan><tspan>`</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> impl&lt;T, K&gt; Foo&lt;K&gt; for T where T: Bar&lt;K&gt;</tspan>
<tspan x="10px" y="226px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required for `Struct` to implement `Foo&lt;i32&gt;`</tspan>
</tspan>
<tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">------</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">unsatisfied trait bound introduced here</tspan>
<tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:11:12</tspan>
</tspan>
<tspan x="10px" y="262px">
<tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
</tspan>
<tspan x="10px" y="280px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 1 previous error</tspan>
<tspan x="10px" y="280px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> impl&lt;T, K&gt; Foo&lt;K&gt; for T where T: Bar&lt;K&gt;</tspan>
</tspan>
<tspan x="10px" y="298px">
<tspan x="10px" y="298px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">------</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">unsatisfied trait bound introduced here</tspan>
</tspan>
<tspan x="10px" y="316px"><tspan class="bold">For more information about this error, try `rustc --explain E0277`.</tspan>
<tspan x="10px" y="316px">
</tspan>
<tspan x="10px" y="334px">
<tspan x="10px" y="334px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 1 previous error</tspan>
</tspan>
<tspan x="10px" y="352px">
</tspan>
<tspan x="10px" y="370px"><tspan class="bold">For more information about this error, try `rustc --explain E0277`.</tspan>
</tspan>
<tspan x="10px" y="388px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -32,7 +32,8 @@ LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
LL | self
| ---- return type was inferred to be `Bar` here
|
= help: the trait `Foo<char>` is implemented for `Bar`
= help: the trait `Foo<u8>` is not implemented for `Bar`
but trait `Foo<char>` is implemented for it
= help: for that trait implementation, expected `char`, found `u8`
error: aborting due to 3 previous errors

View File

@ -12,6 +12,9 @@ error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)`
|
LL | fn foo<T: Default>() -> Self::E {
| ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
...
LL | (S::default(), T::default())
| ---------------------------- return type was inferred to be `(S, T)` here
|
= note: required because it appears within the type `(S, T)`
help: consider further restricting this bound
@ -24,6 +27,9 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)`
|
LL | fn foo<T: Default>() -> Self::E {
| ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
...
LL | (S::default(), T::default())
| ---------------------------- return type was inferred to be `(S, T)` here
|
= note: required because it appears within the type `(S, T)`
help: consider further restricting this bound

View File

@ -3,6 +3,9 @@ error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:15:9: 15:14}:
|
LL | fn foo<T>() -> Self::E {
| ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:15:9: 15:14}`
LL |
LL | async {}
| -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:15:9: 15:14}` here
error: aborting due to 1 previous error

View File

@ -29,7 +29,8 @@ error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
= help: the trait `Raw<_>` is not implemented for `RawImpl<_>`
but trait `Raw<[_]>` is implemented for it
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:33:35
|
@ -67,7 +68,8 @@ error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
|
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: the trait `Raw<()>` is not implemented for `RawImpl<()>`
but trait `Raw<[()]>` is implemented for it
= help: for that trait implementation, expected `[()]`, found `()`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:33:35

View File

@ -83,7 +83,8 @@ error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied
LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {}
| ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()`
|
= help: the trait `Qux<'_>` is implemented for `()`
= help: the trait `Qux<'b>` is not implemented for `&'a ()`
but trait `Qux<'_>` is implemented for `()`
= help: for that trait implementation, expected `()`, found `&'a ()`
error: implementation of `Bar` is not general enough
@ -101,7 +102,8 @@ error[E0277]: the trait bound `for<'a, 'b> &'a (): Qux<'b>` is not satisfied
LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {}
| ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Qux<'b>` is not implemented for `&'a ()`
|
= help: the trait `Qux<'_>` is implemented for `()`
= help: the trait `Qux<'b>` is not implemented for `&'a ()`
but trait `Qux<'_>` is implemented for `()`
= help: for that trait implementation, expected `()`, found `&'a ()`
error: aborting due to 9 previous errors

Some files were not shown because too many files have changed in this diff Show More