mirror of https://github.com/rust-lang/rust.git
Auto merge of #117387 - fmease:rollup-5958nsf, r=fmease
Rollup of 8 pull requests Successful merges: - #117147 (Print variadic argument pattern in HIR pretty printer) - #117177 (Use ImageDataType for allocation type) - #117205 (Allows `#[diagnostic::on_unimplemented]` attributes to have multiple) - #117350 (coverage: Replace manual debug indents with nested tracing spans in `counters`) - #117365 (Stabilize inline asm usage with rustc_codegen_cranelift) - #117371 (Ignore RPIT duplicated lifetimes in `opaque_types_defined_by`) - #117382 (Fail typeck for illegal break-with-value) - #117385 (deduce_param_attrs: explain a read-only case) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e324cf0f73
|
@ -1742,14 +1742,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
|
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
|
||||||
// Skip the `...` (`CVarArgs`) trailing arguments from the AST,
|
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
|
||||||
// as they are not explicit in HIR/Ty function signatures.
|
|
||||||
// (instead, the `c_variadic` flag is set to `true`)
|
|
||||||
let mut inputs = &decl.inputs[..];
|
|
||||||
if decl.c_variadic() {
|
|
||||||
inputs = &inputs[..inputs.len() - 1];
|
|
||||||
}
|
|
||||||
self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind {
|
|
||||||
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
|
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
|
||||||
_ => Ident::new(kw::Empty, self.lower_span(param.pat.span)),
|
_ => Ident::new(kw::Empty, self.lower_span(param.pat.span)),
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -35,9 +35,9 @@ smallvec = "1.8.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Enable features not ready to be enabled when compiling as part of rustc
|
# Enable features not ready to be enabled when compiling as part of rustc
|
||||||
unstable-features = ["jit", "inline_asm"]
|
unstable-features = ["jit", "inline_asm_sym"]
|
||||||
jit = ["cranelift-jit", "libloading"]
|
jit = ["cranelift-jit", "libloading"]
|
||||||
inline_asm = []
|
inline_asm_sym = []
|
||||||
|
|
||||||
[package.metadata.rust-analyzer]
|
[package.metadata.rust-analyzer]
|
||||||
rustc_private = true
|
rustc_private = true
|
||||||
|
|
|
@ -40,22 +40,6 @@ version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9"
|
checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "auxv"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e50430f9beb8effb02399fa81c76eeaa26b05e4f03b09285cad8d079c1af5a3d"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"gcc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.79"
|
version = "1.0.79"
|
||||||
|
@ -388,7 +372,6 @@ dependencies = [
|
||||||
name = "std_detect"
|
name = "std_detect"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"auxv",
|
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"cupid",
|
"cupid",
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2023-10-21"
|
channel = "nightly-2023-10-29"
|
||||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||||
|
|
|
@ -4,7 +4,9 @@ set -e
|
||||||
# Compiletest expects all standard library paths to start with /rustc/FAKE_PREFIX.
|
# Compiletest expects all standard library paths to start with /rustc/FAKE_PREFIX.
|
||||||
# CG_CLIF_STDLIB_REMAP_PATH_PREFIX will cause cg_clif's build system to pass
|
# CG_CLIF_STDLIB_REMAP_PATH_PREFIX will cause cg_clif's build system to pass
|
||||||
# --remap-path-prefix to handle this.
|
# --remap-path-prefix to handle this.
|
||||||
CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
|
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
|
||||||
|
# the LLVM backend isn't compiled in here.
|
||||||
|
CG_CLIF_FORCE_GNU_AS=1 CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
|
||||||
|
|
||||||
echo "[SETUP] Rust fork"
|
echo "[SETUP] Rust fork"
|
||||||
git clone https://github.com/rust-lang/rust.git || true
|
git clone https://github.com/rust-lang/rust.git || true
|
||||||
|
|
|
@ -11,5 +11,7 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
|
||||||
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
||||||
cp -r ../src compiler/rustc_codegen_cranelift/src
|
cp -r ../src compiler/rustc_codegen_cranelift/src
|
||||||
|
|
||||||
./x.py build --stage 1 library/std
|
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
|
||||||
|
# the LLVM backend isn't compiled in here.
|
||||||
|
CG_CLIF_FORCE_GNU_AS=1 ./x.py build --stage 1 library/std
|
||||||
popd
|
popd
|
||||||
|
|
|
@ -46,6 +46,13 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
|
||||||
global_asm.push_str(&string);
|
global_asm.push_str(&string);
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SymFn { anon_const } => {
|
InlineAsmOperand::SymFn { anon_const } => {
|
||||||
|
if cfg!(not(feature = "inline_asm_sym")) {
|
||||||
|
tcx.sess.span_err(
|
||||||
|
item.span,
|
||||||
|
"asm! and global_asm! sym operands are not yet supported",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
|
let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
|
||||||
let instance = match ty.kind() {
|
let instance = match ty.kind() {
|
||||||
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
||||||
|
@ -57,6 +64,13 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
|
||||||
global_asm.push_str(symbol.name);
|
global_asm.push_str(symbol.name);
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SymStatic { path: _, def_id } => {
|
InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||||
|
if cfg!(not(feature = "inline_asm_sym")) {
|
||||||
|
tcx.sess.span_err(
|
||||||
|
item.span,
|
||||||
|
"asm! and global_asm! sym operands are not yet supported",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
|
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
|
||||||
let symbol = tcx.symbol_name(instance);
|
let symbol = tcx.symbol_name(instance);
|
||||||
global_asm.push_str(symbol.name);
|
global_asm.push_str(symbol.name);
|
||||||
|
@ -81,22 +95,23 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn asm_supported(tcx: TyCtxt<'_>) -> bool {
|
|
||||||
cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct GlobalAsmConfig {
|
pub(crate) struct GlobalAsmConfig {
|
||||||
asm_enabled: bool,
|
|
||||||
assembler: PathBuf,
|
assembler: PathBuf,
|
||||||
|
target: String,
|
||||||
pub(crate) output_filenames: Arc<OutputFilenames>,
|
pub(crate) output_filenames: Arc<OutputFilenames>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalAsmConfig {
|
impl GlobalAsmConfig {
|
||||||
pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
|
pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
|
||||||
GlobalAsmConfig {
|
GlobalAsmConfig {
|
||||||
asm_enabled: asm_supported(tcx),
|
|
||||||
assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"),
|
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, .. } => {
|
||||||
|
path_for_rustdoc.to_str().unwrap().to_owned()
|
||||||
|
}
|
||||||
|
},
|
||||||
output_filenames: tcx.output_filenames(()).clone(),
|
output_filenames: tcx.output_filenames(()).clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,21 +126,6 @@ pub(crate) fn compile_global_asm(
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.asm_enabled {
|
|
||||||
if global_asm.contains("__rust_probestack") {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg!(not(feature = "inline_asm")) {
|
|
||||||
return Err(
|
|
||||||
"asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift"
|
|
||||||
.to_owned(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Err("asm! and global_asm! are not yet supported on Windows".to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove all LLVM style comments
|
// Remove all LLVM style comments
|
||||||
let mut global_asm = global_asm
|
let mut global_asm = global_asm
|
||||||
.lines()
|
.lines()
|
||||||
|
@ -134,10 +134,13 @@ pub(crate) fn compile_global_asm(
|
||||||
.join("\n");
|
.join("\n");
|
||||||
global_asm.push('\n');
|
global_asm.push('\n');
|
||||||
|
|
||||||
let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name));
|
let global_asm_object_file = add_file_stem_postfix(
|
||||||
|
config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)),
|
||||||
|
".asm",
|
||||||
|
);
|
||||||
|
|
||||||
// Assemble `global_asm`
|
// Assemble `global_asm`
|
||||||
let global_asm_object_file = add_file_stem_postfix(output_object_file, ".asm");
|
if option_env!("CG_CLIF_FORCE_GNU_AS").is_some() {
|
||||||
let mut child = Command::new(&config.assembler)
|
let mut child = Command::new(&config.assembler)
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(&global_asm_object_file)
|
.arg(&global_asm_object_file)
|
||||||
|
@ -149,6 +152,50 @@ pub(crate) fn compile_global_asm(
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
return Err(format!("Failed to assemble `{}`", global_asm));
|
return Err(format!("Failed to assemble `{}`", global_asm));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let mut child = Command::new(std::env::current_exe().unwrap())
|
||||||
|
.arg("--target")
|
||||||
|
.arg(&config.target)
|
||||||
|
.arg("--crate-type")
|
||||||
|
.arg("staticlib")
|
||||||
|
.arg("--emit")
|
||||||
|
.arg("obj")
|
||||||
|
.arg("-o")
|
||||||
|
.arg(&global_asm_object_file)
|
||||||
|
.arg("-")
|
||||||
|
.arg("-Abad_asm_style")
|
||||||
|
.arg("-Zcodegen-backend=llvm")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.expect("Failed to spawn `as`.");
|
||||||
|
let mut stdin = child.stdin.take().unwrap();
|
||||||
|
stdin
|
||||||
|
.write_all(
|
||||||
|
br####"
|
||||||
|
#![feature(decl_macro, no_core, rustc_attrs)]
|
||||||
|
#![allow(internal_features)]
|
||||||
|
#![no_core]
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
#[rustc_macro_transparency = "semitransparent"]
|
||||||
|
macro global_asm() { /* compiler built-in */ }
|
||||||
|
global_asm!(r###"
|
||||||
|
"####,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
stdin.write_all(global_asm.as_bytes()).unwrap();
|
||||||
|
stdin
|
||||||
|
.write_all(
|
||||||
|
br####"
|
||||||
|
"###);
|
||||||
|
"####,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
std::mem::drop(stdin);
|
||||||
|
let status = child.wait().expect("Failed to wait for `as`.");
|
||||||
|
if !status.success() {
|
||||||
|
return Err(format!("Failed to assemble `{}`", global_asm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Some(global_asm_object_file))
|
Ok(Some(global_asm_object_file))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use rustc_span::sym;
|
||||||
use rustc_target::asm::*;
|
use rustc_target::asm::*;
|
||||||
use target_lexicon::BinaryFormat;
|
use target_lexicon::BinaryFormat;
|
||||||
|
|
||||||
use crate::global_asm::asm_supported;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
enum CInlineAsmOperand<'tcx> {
|
enum CInlineAsmOperand<'tcx> {
|
||||||
|
@ -45,211 +44,14 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
||||||
) {
|
) {
|
||||||
// FIXME add .eh_frame unwind info directives
|
// FIXME add .eh_frame unwind info directives
|
||||||
|
|
||||||
if !asm_supported(fx.tcx) {
|
// Used by panic_abort on Windows, but uses a syntax which only happens to work with
|
||||||
if template.is_empty() {
|
// asm!() by accident and breaks with the GNU assembler as well as global_asm!() for
|
||||||
let destination_block = fx.get_block(destination.unwrap());
|
// the LLVM backend.
|
||||||
fx.bcx.ins().jump(destination_block, &[]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by panic_abort
|
|
||||||
if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
|
if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
|
||||||
fx.bcx.ins().trap(TrapCode::User(1));
|
fx.bcx.ins().trap(TrapCode::User(1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by stdarch
|
|
||||||
if template[0] == InlineAsmTemplatePiece::String("mov ".to_string())
|
|
||||||
&& matches!(
|
|
||||||
template[1],
|
|
||||||
InlineAsmTemplatePiece::Placeholder {
|
|
||||||
operand_idx: 0,
|
|
||||||
modifier: Some('r'),
|
|
||||||
span: _
|
|
||||||
}
|
|
||||||
)
|
|
||||||
&& template[2] == InlineAsmTemplatePiece::String(", rbx".to_string())
|
|
||||||
&& template[3] == InlineAsmTemplatePiece::String("\n".to_string())
|
|
||||||
&& template[4] == InlineAsmTemplatePiece::String("cpuid".to_string())
|
|
||||||
&& template[5] == InlineAsmTemplatePiece::String("\n".to_string())
|
|
||||||
&& template[6] == InlineAsmTemplatePiece::String("xchg ".to_string())
|
|
||||||
&& matches!(
|
|
||||||
template[7],
|
|
||||||
InlineAsmTemplatePiece::Placeholder {
|
|
||||||
operand_idx: 0,
|
|
||||||
modifier: Some('r'),
|
|
||||||
span: _
|
|
||||||
}
|
|
||||||
)
|
|
||||||
&& template[8] == InlineAsmTemplatePiece::String(", rbx".to_string())
|
|
||||||
{
|
|
||||||
assert_eq!(operands.len(), 4);
|
|
||||||
let (leaf, eax_place) = match operands[1] {
|
|
||||||
InlineAsmOperand::InOut {
|
|
||||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
|
|
||||||
late: _,
|
|
||||||
ref in_value,
|
|
||||||
out_place: Some(out_place),
|
|
||||||
} => (
|
|
||||||
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
|
|
||||||
crate::base::codegen_place(fx, out_place),
|
|
||||||
),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let ebx_place = match operands[0] {
|
|
||||||
InlineAsmOperand::Out {
|
|
||||||
reg:
|
|
||||||
InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
|
|
||||||
X86InlineAsmRegClass::reg,
|
|
||||||
)),
|
|
||||||
late: _,
|
|
||||||
place: Some(place),
|
|
||||||
} => crate::base::codegen_place(fx, place),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let (sub_leaf, ecx_place) = match operands[2] {
|
|
||||||
InlineAsmOperand::InOut {
|
|
||||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
|
|
||||||
late: _,
|
|
||||||
ref in_value,
|
|
||||||
out_place: Some(out_place),
|
|
||||||
} => (
|
|
||||||
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
|
|
||||||
crate::base::codegen_place(fx, out_place),
|
|
||||||
),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let edx_place = match operands[3] {
|
|
||||||
InlineAsmOperand::Out {
|
|
||||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
|
|
||||||
late: _,
|
|
||||||
place: Some(place),
|
|
||||||
} => crate::base::codegen_place(fx, place),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
|
|
||||||
|
|
||||||
eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
|
|
||||||
ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
|
|
||||||
ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
|
|
||||||
edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
|
|
||||||
let destination_block = fx.get_block(destination.unwrap());
|
|
||||||
fx.bcx.ins().jump(destination_block, &[]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by compiler-builtins
|
|
||||||
if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
|
|
||||||
// ___chkstk, ___chkstk_ms and __alloca are only used on Windows
|
|
||||||
crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
|
|
||||||
return;
|
|
||||||
} else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
|
|
||||||
crate::trap::trap_unimplemented(fx, "Alloca is not supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by core::hint::spin_loop()
|
|
||||||
if template[0]
|
|
||||||
== InlineAsmTemplatePiece::String(".insn i 0x0F, 0, x0, x0, 0x010".to_string())
|
|
||||||
&& template.len() == 1
|
|
||||||
{
|
|
||||||
let destination_block = fx.get_block(destination.unwrap());
|
|
||||||
fx.bcx.ins().jump(destination_block, &[]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by measureme
|
|
||||||
if template[0] == InlineAsmTemplatePiece::String("xor %eax, %eax".to_string())
|
|
||||||
&& template[1] == InlineAsmTemplatePiece::String("\n".to_string())
|
|
||||||
&& template[2] == InlineAsmTemplatePiece::String("mov %rbx, ".to_string())
|
|
||||||
&& matches!(
|
|
||||||
template[3],
|
|
||||||
InlineAsmTemplatePiece::Placeholder {
|
|
||||||
operand_idx: 0,
|
|
||||||
modifier: Some('r'),
|
|
||||||
span: _
|
|
||||||
}
|
|
||||||
)
|
|
||||||
&& template[4] == InlineAsmTemplatePiece::String("\n".to_string())
|
|
||||||
&& template[5] == InlineAsmTemplatePiece::String("cpuid".to_string())
|
|
||||||
&& template[6] == InlineAsmTemplatePiece::String("\n".to_string())
|
|
||||||
&& template[7] == InlineAsmTemplatePiece::String("mov ".to_string())
|
|
||||||
&& matches!(
|
|
||||||
template[8],
|
|
||||||
InlineAsmTemplatePiece::Placeholder {
|
|
||||||
operand_idx: 0,
|
|
||||||
modifier: Some('r'),
|
|
||||||
span: _
|
|
||||||
}
|
|
||||||
)
|
|
||||||
&& template[9] == InlineAsmTemplatePiece::String(", %rbx".to_string())
|
|
||||||
{
|
|
||||||
let destination_block = fx.get_block(destination.unwrap());
|
|
||||||
fx.bcx.ins().jump(destination_block, &[]);
|
|
||||||
return;
|
|
||||||
} else if template[0] == InlineAsmTemplatePiece::String("rdpmc".to_string()) {
|
|
||||||
// Return zero dummy values for all performance counters
|
|
||||||
match operands[0] {
|
|
||||||
InlineAsmOperand::In {
|
|
||||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
|
|
||||||
value: _,
|
|
||||||
} => {}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let lo = match operands[1] {
|
|
||||||
InlineAsmOperand::Out {
|
|
||||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
|
|
||||||
late: true,
|
|
||||||
place: Some(place),
|
|
||||||
} => crate::base::codegen_place(fx, place),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let hi = match operands[2] {
|
|
||||||
InlineAsmOperand::Out {
|
|
||||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
|
|
||||||
late: true,
|
|
||||||
place: Some(place),
|
|
||||||
} => crate::base::codegen_place(fx, place),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let u32_layout = fx.layout_of(fx.tcx.types.u32);
|
|
||||||
let zero = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
lo.write_cvalue(fx, CValue::by_val(zero, u32_layout));
|
|
||||||
hi.write_cvalue(fx, CValue::by_val(zero, u32_layout));
|
|
||||||
|
|
||||||
let destination_block = fx.get_block(destination.unwrap());
|
|
||||||
fx.bcx.ins().jump(destination_block, &[]);
|
|
||||||
return;
|
|
||||||
} else if template[0] == InlineAsmTemplatePiece::String("lock xadd ".to_string())
|
|
||||||
&& matches!(
|
|
||||||
template[1],
|
|
||||||
InlineAsmTemplatePiece::Placeholder { operand_idx: 1, modifier: None, span: _ }
|
|
||||||
)
|
|
||||||
&& template[2] == InlineAsmTemplatePiece::String(", (".to_string())
|
|
||||||
&& matches!(
|
|
||||||
template[3],
|
|
||||||
InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: None, span: _ }
|
|
||||||
)
|
|
||||||
&& template[4] == InlineAsmTemplatePiece::String(")".to_string())
|
|
||||||
{
|
|
||||||
let destination_block = fx.get_block(destination.unwrap());
|
|
||||||
fx.bcx.ins().jump(destination_block, &[]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg!(not(feature = "inline_asm")) {
|
|
||||||
fx.tcx.sess.span_err(
|
|
||||||
span,
|
|
||||||
"asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift",
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
fx.tcx.sess.span_err(span, "asm! and global_asm! are not yet supported on Windows");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let operands = operands
|
let operands = operands
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|operand| match *operand {
|
.map(|operand| match *operand {
|
||||||
|
@ -280,6 +82,12 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
||||||
CInlineAsmOperand::Const { value }
|
CInlineAsmOperand::Const { value }
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SymFn { ref value } => {
|
InlineAsmOperand::SymFn { ref value } => {
|
||||||
|
if cfg!(not(feature = "inline_asm_sym")) {
|
||||||
|
fx.tcx
|
||||||
|
.sess
|
||||||
|
.span_err(span, "asm! and global_asm! sym operands are not yet supported");
|
||||||
|
}
|
||||||
|
|
||||||
let const_ = fx.monomorphize(value.const_);
|
let const_ = fx.monomorphize(value.const_);
|
||||||
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
||||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
//! Emulation of a subset of the cpuid x86 instruction.
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
/// Emulates a subset of the cpuid x86 instruction.
|
|
||||||
///
|
|
||||||
/// This emulates an intel cpu with sse and sse2 support, but which doesn't support anything else.
|
|
||||||
pub(crate) fn codegen_cpuid_call<'tcx>(
|
|
||||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
|
||||||
leaf: Value,
|
|
||||||
_sub_leaf: Value,
|
|
||||||
) -> (Value, Value, Value, Value) {
|
|
||||||
let leaf_0 = fx.bcx.create_block();
|
|
||||||
let leaf_1 = fx.bcx.create_block();
|
|
||||||
let leaf_7 = fx.bcx.create_block();
|
|
||||||
let leaf_8000_0000 = fx.bcx.create_block();
|
|
||||||
let leaf_8000_0001 = fx.bcx.create_block();
|
|
||||||
let unsupported_leaf = fx.bcx.create_block();
|
|
||||||
|
|
||||||
let dest = fx.bcx.create_block();
|
|
||||||
let eax = fx.bcx.append_block_param(dest, types::I32);
|
|
||||||
let ebx = fx.bcx.append_block_param(dest, types::I32);
|
|
||||||
let ecx = fx.bcx.append_block_param(dest, types::I32);
|
|
||||||
let edx = fx.bcx.append_block_param(dest, types::I32);
|
|
||||||
|
|
||||||
let mut switch = cranelift_frontend::Switch::new();
|
|
||||||
switch.set_entry(0, leaf_0);
|
|
||||||
switch.set_entry(1, leaf_1);
|
|
||||||
switch.set_entry(7, leaf_7);
|
|
||||||
switch.set_entry(0x8000_0000, leaf_8000_0000);
|
|
||||||
switch.set_entry(0x8000_0001, leaf_8000_0001);
|
|
||||||
switch.emit(&mut fx.bcx, leaf, unsupported_leaf);
|
|
||||||
|
|
||||||
fx.bcx.switch_to_block(leaf_0);
|
|
||||||
let max_basic_leaf = fx.bcx.ins().iconst(types::I32, 1);
|
|
||||||
let vend0 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"Genu")));
|
|
||||||
let vend2 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ineI")));
|
|
||||||
let vend1 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ntel")));
|
|
||||||
fx.bcx.ins().jump(dest, &[max_basic_leaf, vend0, vend1, vend2]);
|
|
||||||
|
|
||||||
fx.bcx.switch_to_block(leaf_1);
|
|
||||||
let cpu_signature = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
let additional_information = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
let ecx_features = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
|
|
||||||
fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);
|
|
||||||
|
|
||||||
fx.bcx.switch_to_block(leaf_7);
|
|
||||||
// This leaf technically has subleaves, but we just return zero for all subleaves.
|
|
||||||
let zero = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]);
|
|
||||||
|
|
||||||
fx.bcx.switch_to_block(leaf_8000_0000);
|
|
||||||
let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
let zero = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
fx.bcx.ins().jump(dest, &[extended_max_basic_leaf, zero, zero, zero]);
|
|
||||||
|
|
||||||
fx.bcx.switch_to_block(leaf_8000_0001);
|
|
||||||
let zero = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
let proc_info_ecx = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
let proc_info_edx = fx.bcx.ins().iconst(types::I32, 0);
|
|
||||||
fx.bcx.ins().jump(dest, &[zero, zero, proc_info_ecx, proc_info_edx]);
|
|
||||||
|
|
||||||
fx.bcx.switch_to_block(unsupported_leaf);
|
|
||||||
crate::trap::trap_unimplemented(
|
|
||||||
fx,
|
|
||||||
"__cpuid_count arch intrinsic doesn't yet support specified leaf",
|
|
||||||
);
|
|
||||||
|
|
||||||
fx.bcx.switch_to_block(dest);
|
|
||||||
fx.bcx.ins().nop();
|
|
||||||
|
|
||||||
(eax, ebx, ecx, edx)
|
|
||||||
}
|
|
|
@ -12,7 +12,6 @@ macro_rules! intrinsic_args {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod cpuid;
|
|
||||||
mod llvm;
|
mod llvm;
|
||||||
mod llvm_aarch64;
|
mod llvm_aarch64;
|
||||||
mod llvm_x86;
|
mod llvm_x86;
|
||||||
|
@ -25,7 +24,6 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||||
use rustc_middle::ty::GenericArgsRef;
|
use rustc_middle::ty::GenericArgsRef;
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
|
|
||||||
pub(crate) use self::cpuid::codegen_cpuid_call;
|
|
||||||
pub(crate) use self::llvm::codegen_llvm_intrinsic_call;
|
pub(crate) use self::llvm::codegen_llvm_intrinsic_call;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
|
|
@ -502,13 +502,13 @@ impl<'a> State<'a> {
|
||||||
self.word(";");
|
self.word(";");
|
||||||
self.end(); // end the outer cbox
|
self.end(); // end the outer cbox
|
||||||
}
|
}
|
||||||
hir::ItemKind::Fn(ref sig, param_names, body) => {
|
hir::ItemKind::Fn(ref sig, generics, body) => {
|
||||||
self.head("");
|
self.head("");
|
||||||
self.print_fn(
|
self.print_fn(
|
||||||
sig.decl,
|
sig.decl,
|
||||||
sig.header,
|
sig.header,
|
||||||
Some(item.ident.name),
|
Some(item.ident.name),
|
||||||
param_names,
|
generics,
|
||||||
&[],
|
&[],
|
||||||
Some(body),
|
Some(body),
|
||||||
);
|
);
|
||||||
|
@ -1948,11 +1948,10 @@ impl<'a> State<'a> {
|
||||||
self.print_generic_params(generics.params);
|
self.print_generic_params(generics.params);
|
||||||
|
|
||||||
self.popen();
|
self.popen();
|
||||||
let mut i = 0;
|
|
||||||
// Make sure we aren't supplied *both* `arg_names` and `body_id`.
|
// Make sure we aren't supplied *both* `arg_names` and `body_id`.
|
||||||
assert!(arg_names.is_empty() || body_id.is_none());
|
assert!(arg_names.is_empty() || body_id.is_none());
|
||||||
self.commasep(Inconsistent, decl.inputs, |s, ty| {
|
let mut i = 0;
|
||||||
s.ibox(INDENT_UNIT);
|
let mut print_arg = |s: &mut Self| {
|
||||||
if let Some(arg_name) = arg_names.get(i) {
|
if let Some(arg_name) = arg_names.get(i) {
|
||||||
s.word(arg_name.to_string());
|
s.word(arg_name.to_string());
|
||||||
s.word(":");
|
s.word(":");
|
||||||
|
@ -1963,11 +1962,17 @@ impl<'a> State<'a> {
|
||||||
s.space();
|
s.space();
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
|
};
|
||||||
|
self.commasep(Inconsistent, decl.inputs, |s, ty| {
|
||||||
|
s.ibox(INDENT_UNIT);
|
||||||
|
print_arg(s);
|
||||||
s.print_type(ty);
|
s.print_type(ty);
|
||||||
s.end()
|
s.end();
|
||||||
});
|
});
|
||||||
if decl.c_variadic {
|
if decl.c_variadic {
|
||||||
self.word(", ...");
|
self.word(", ");
|
||||||
|
print_arg(self);
|
||||||
|
self.word("...");
|
||||||
}
|
}
|
||||||
self.pclose();
|
self.pclose();
|
||||||
|
|
||||||
|
|
|
@ -625,10 +625,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let coerce_to = match opt_coerce_to {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
// If the loop context is not a `loop { }`, then break with
|
// If the loop context is not a `loop { }`, then break with
|
||||||
// a value is illegal, and `opt_coerce_to` will be `None`.
|
// a value is illegal, and `opt_coerce_to` will be `None`.
|
||||||
// Just set expectation to error in that case.
|
// Return error in that case (#114529).
|
||||||
let coerce_to = opt_coerce_to.unwrap_or_else(|| Ty::new_misc_error(tcx));
|
return Ty::new_misc_error(tcx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Recurse without `enclosing_breakables` borrowed.
|
// Recurse without `enclosing_breakables` borrowed.
|
||||||
e_ty = self.check_expr_with_hint(e, coerce_to);
|
e_ty = self.check_expr_with_hint(e, coerce_to);
|
||||||
|
|
|
@ -460,7 +460,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
/// Checks whether each generic argument is simply a unique generic parameter.
|
/// Checks whether each generic argument is simply a unique generic parameter.
|
||||||
pub fn uses_unique_generic_params(
|
pub fn uses_unique_generic_params(
|
||||||
self,
|
self,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: &[ty::GenericArg<'tcx>],
|
||||||
ignore_regions: CheckRegions,
|
ignore_regions: CheckRegions,
|
||||||
) -> Result<(), NotUniqueParam<'tcx>> {
|
) -> Result<(), NotUniqueParam<'tcx>> {
|
||||||
let mut seen = GrowableBitSet::default();
|
let mut seen = GrowableBitSet::default();
|
||||||
|
|
|
@ -12,8 +12,6 @@ use rustc_middle::mir::coverage::*;
|
||||||
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
const NESTED_INDENT: &str = " ";
|
|
||||||
|
|
||||||
/// The coverage counter or counter expression associated with a particular
|
/// The coverage counter or counter expression associated with a particular
|
||||||
/// BCB node or BCB edge.
|
/// BCB node or BCB edge.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -346,23 +344,11 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> Result<CovTerm, Error> {
|
fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> Result<CovTerm, Error> {
|
||||||
self.recursive_get_or_make_counter_operand(bcb, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recursive_get_or_make_counter_operand(
|
|
||||||
&mut self,
|
|
||||||
bcb: BasicCoverageBlock,
|
|
||||||
debug_indent_level: usize,
|
|
||||||
) -> Result<CovTerm, Error> {
|
|
||||||
// If the BCB already has a counter, return it.
|
// If the BCB already has a counter, return it.
|
||||||
if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] {
|
if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] {
|
||||||
debug!(
|
debug!("{bcb:?} already has a counter: {counter_kind:?}");
|
||||||
"{}{:?} already has a counter: {:?}",
|
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
|
||||||
bcb,
|
|
||||||
counter_kind,
|
|
||||||
);
|
|
||||||
return Ok(counter_kind.as_term());
|
return Ok(counter_kind.as_term());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,20 +359,12 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) {
|
if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) {
|
||||||
let counter_kind = self.coverage_counters.make_counter();
|
let counter_kind = self.coverage_counters.make_counter();
|
||||||
if one_path_to_target {
|
if one_path_to_target {
|
||||||
debug!(
|
debug!("{bcb:?} gets a new counter: {counter_kind:?}");
|
||||||
"{}{:?} gets a new counter: {:?}",
|
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
|
||||||
bcb,
|
|
||||||
counter_kind,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!(
|
||||||
"{}{:?} has itself as its own predecessor. It can't be part of its own \
|
"{bcb:?} has itself as its own predecessor. It can't be part of its own \
|
||||||
Expression sum, so it will get its own new counter: {:?}. (Note, the compiled \
|
Expression sum, so it will get its own new counter: {counter_kind:?}. \
|
||||||
code will generate an infinite loop.)",
|
(Note, the compiled code will generate an infinite loop.)",
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
|
||||||
bcb,
|
|
||||||
counter_kind,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return self.coverage_counters.set_bcb_counter(bcb, counter_kind);
|
return self.coverage_counters.set_bcb_counter(bcb, counter_kind);
|
||||||
|
@ -396,24 +374,14 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
// counters and/or expressions of its incoming edges. This will recursively get or create
|
// counters and/or expressions of its incoming edges. This will recursively get or create
|
||||||
// counters for those incoming edges first, then call `make_expression()` to sum them up,
|
// counters for those incoming edges first, then call `make_expression()` to sum them up,
|
||||||
// with additional intermediate expressions as needed.
|
// with additional intermediate expressions as needed.
|
||||||
|
let _sumup_debug_span = debug_span!("(preparing sum-up expression)").entered();
|
||||||
|
|
||||||
let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter();
|
let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter();
|
||||||
debug!(
|
let first_edge_counter_operand =
|
||||||
"{}{:?} has multiple incoming edges and will get an expression that sums them up...",
|
self.get_or_make_edge_counter_operand(predecessors.next().unwrap(), bcb)?;
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
|
||||||
bcb,
|
|
||||||
);
|
|
||||||
let first_edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
|
|
||||||
predecessors.next().unwrap(),
|
|
||||||
bcb,
|
|
||||||
debug_indent_level + 1,
|
|
||||||
)?;
|
|
||||||
let mut some_sumup_edge_counter_operand = None;
|
let mut some_sumup_edge_counter_operand = None;
|
||||||
for predecessor in predecessors {
|
for predecessor in predecessors {
|
||||||
let edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
|
let edge_counter_operand = self.get_or_make_edge_counter_operand(predecessor, bcb)?;
|
||||||
predecessor,
|
|
||||||
bcb,
|
|
||||||
debug_indent_level + 1,
|
|
||||||
)?;
|
|
||||||
if let Some(sumup_edge_counter_operand) =
|
if let Some(sumup_edge_counter_operand) =
|
||||||
some_sumup_edge_counter_operand.replace(edge_counter_operand)
|
some_sumup_edge_counter_operand.replace(edge_counter_operand)
|
||||||
{
|
{
|
||||||
|
@ -422,11 +390,7 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
Op::Add,
|
Op::Add,
|
||||||
edge_counter_operand,
|
edge_counter_operand,
|
||||||
);
|
);
|
||||||
debug!(
|
debug!("new intermediate expression: {intermediate_expression:?}");
|
||||||
"{}new intermediate expression: {:?}",
|
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
|
||||||
intermediate_expression
|
|
||||||
);
|
|
||||||
let intermediate_expression_operand = intermediate_expression.as_term();
|
let intermediate_expression_operand = intermediate_expression.as_term();
|
||||||
some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
|
some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
|
||||||
}
|
}
|
||||||
|
@ -436,59 +400,36 @@ impl<'a> MakeBcbCounters<'a> {
|
||||||
Op::Add,
|
Op::Add,
|
||||||
some_sumup_edge_counter_operand.unwrap(),
|
some_sumup_edge_counter_operand.unwrap(),
|
||||||
);
|
);
|
||||||
debug!(
|
drop(_sumup_debug_span);
|
||||||
"{}{:?} gets a new counter (sum of predecessor counters): {:?}",
|
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
debug!("{bcb:?} gets a new counter (sum of predecessor counters): {counter_kind:?}");
|
||||||
bcb,
|
|
||||||
counter_kind
|
|
||||||
);
|
|
||||||
self.coverage_counters.set_bcb_counter(bcb, counter_kind)
|
self.coverage_counters.set_bcb_counter(bcb, counter_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn get_or_make_edge_counter_operand(
|
fn get_or_make_edge_counter_operand(
|
||||||
&mut self,
|
&mut self,
|
||||||
from_bcb: BasicCoverageBlock,
|
from_bcb: BasicCoverageBlock,
|
||||||
to_bcb: BasicCoverageBlock,
|
to_bcb: BasicCoverageBlock,
|
||||||
) -> Result<CovTerm, Error> {
|
|
||||||
self.recursive_get_or_make_edge_counter_operand(from_bcb, to_bcb, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recursive_get_or_make_edge_counter_operand(
|
|
||||||
&mut self,
|
|
||||||
from_bcb: BasicCoverageBlock,
|
|
||||||
to_bcb: BasicCoverageBlock,
|
|
||||||
debug_indent_level: usize,
|
|
||||||
) -> Result<CovTerm, Error> {
|
) -> Result<CovTerm, Error> {
|
||||||
// If the source BCB has only one successor (assumed to be the given target), an edge
|
// If the source BCB has only one successor (assumed to be the given target), an edge
|
||||||
// counter is unnecessary. Just get or make a counter for the source BCB.
|
// counter is unnecessary. Just get or make a counter for the source BCB.
|
||||||
let successors = self.bcb_successors(from_bcb).iter();
|
let successors = self.bcb_successors(from_bcb).iter();
|
||||||
if successors.len() == 1 {
|
if successors.len() == 1 {
|
||||||
return self.recursive_get_or_make_counter_operand(from_bcb, debug_indent_level + 1);
|
return self.get_or_make_counter_operand(from_bcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the edge already has a counter, return it.
|
// If the edge already has a counter, return it.
|
||||||
if let Some(counter_kind) =
|
if let Some(counter_kind) =
|
||||||
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
|
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
|
||||||
{
|
{
|
||||||
debug!(
|
debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}");
|
||||||
"{}Edge {:?}->{:?} already has a counter: {:?}",
|
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
|
||||||
from_bcb,
|
|
||||||
to_bcb,
|
|
||||||
counter_kind
|
|
||||||
);
|
|
||||||
return Ok(counter_kind.as_term());
|
return Ok(counter_kind.as_term());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a new counter to count this edge.
|
// Make a new counter to count this edge.
|
||||||
let counter_kind = self.coverage_counters.make_counter();
|
let counter_kind = self.coverage_counters.make_counter();
|
||||||
debug!(
|
debug!("Edge {from_bcb:?}->{to_bcb:?} gets a new counter: {counter_kind:?}");
|
||||||
"{}Edge {:?}->{:?} gets a new counter: {:?}",
|
|
||||||
NESTED_INDENT.repeat(debug_indent_level),
|
|
||||||
from_bcb,
|
|
||||||
to_bcb,
|
|
||||||
counter_kind
|
|
||||||
);
|
|
||||||
self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind)
|
self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
|
||||||
// Whether mutating though a `&raw const` is allowed is still undecided, so we
|
// Whether mutating though a `&raw const` is allowed is still undecided, so we
|
||||||
// disable any sketchy `readonly` optimizations for now.
|
// disable any sketchy `readonly` optimizations for now.
|
||||||
// But we only need to do this if the pointer would point into the argument.
|
// But we only need to do this if the pointer would point into the argument.
|
||||||
|
// IOW: for indirect places, like `&raw (*local).field`, this surely cannot mutate `local`.
|
||||||
!place.is_indirect()
|
!place.is_indirect()
|
||||||
}
|
}
|
||||||
PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
|
PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
|
||||||
|
|
|
@ -319,7 +319,7 @@ pub struct OnUnimplementedDirective {
|
||||||
pub subcommands: Vec<OnUnimplementedDirective>,
|
pub subcommands: Vec<OnUnimplementedDirective>,
|
||||||
pub message: Option<OnUnimplementedFormatString>,
|
pub message: Option<OnUnimplementedFormatString>,
|
||||||
pub label: Option<OnUnimplementedFormatString>,
|
pub label: Option<OnUnimplementedFormatString>,
|
||||||
pub note: Option<OnUnimplementedFormatString>,
|
pub notes: Vec<OnUnimplementedFormatString>,
|
||||||
pub parent_label: Option<OnUnimplementedFormatString>,
|
pub parent_label: Option<OnUnimplementedFormatString>,
|
||||||
pub append_const_msg: Option<AppendConstMessage>,
|
pub append_const_msg: Option<AppendConstMessage>,
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ pub struct OnUnimplementedDirective {
|
||||||
pub struct OnUnimplementedNote {
|
pub struct OnUnimplementedNote {
|
||||||
pub message: Option<String>,
|
pub message: Option<String>,
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
pub note: Option<String>,
|
pub notes: Vec<String>,
|
||||||
pub parent_label: Option<String>,
|
pub parent_label: Option<String>,
|
||||||
// If none, should fall back to a generic message
|
// If none, should fall back to a generic message
|
||||||
pub append_const_msg: Option<AppendConstMessage>,
|
pub append_const_msg: Option<AppendConstMessage>,
|
||||||
|
@ -399,7 +399,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
|
|
||||||
let mut message = None;
|
let mut message = None;
|
||||||
let mut label = None;
|
let mut label = None;
|
||||||
let mut note = None;
|
let mut notes = Vec::new();
|
||||||
let mut parent_label = None;
|
let mut parent_label = None;
|
||||||
let mut subcommands = vec![];
|
let mut subcommands = vec![];
|
||||||
let mut append_const_msg = None;
|
let mut append_const_msg = None;
|
||||||
|
@ -415,11 +415,13 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
label = parse_value(label_)?;
|
label = parse_value(label_)?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if item.has_name(sym::note) && note.is_none() {
|
} else if item.has_name(sym::note) {
|
||||||
if let Some(note_) = item.value_str() {
|
if let Some(note_) = item.value_str() {
|
||||||
note = parse_value(note_)?;
|
if let Some(note) = parse_value(note_)? {
|
||||||
|
notes.push(note);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if item.has_name(sym::parent_label)
|
} else if item.has_name(sym::parent_label)
|
||||||
&& parent_label.is_none()
|
&& parent_label.is_none()
|
||||||
&& !is_diagnostic_namespace_variant
|
&& !is_diagnostic_namespace_variant
|
||||||
|
@ -432,7 +434,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
&& is_root
|
&& is_root
|
||||||
&& message.is_none()
|
&& message.is_none()
|
||||||
&& label.is_none()
|
&& label.is_none()
|
||||||
&& note.is_none()
|
&& notes.is_empty()
|
||||||
&& !is_diagnostic_namespace_variant
|
&& !is_diagnostic_namespace_variant
|
||||||
// FIXME(diagnostic_namespace): disallow filters for now
|
// FIXME(diagnostic_namespace): disallow filters for now
|
||||||
{
|
{
|
||||||
|
@ -487,7 +489,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
subcommands,
|
subcommands,
|
||||||
message,
|
message,
|
||||||
label,
|
label,
|
||||||
note,
|
notes,
|
||||||
parent_label,
|
parent_label,
|
||||||
append_const_msg,
|
append_const_msg,
|
||||||
}))
|
}))
|
||||||
|
@ -505,12 +507,14 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
if let Some(aggr) = aggr {
|
if let Some(aggr) = aggr {
|
||||||
let mut subcommands = aggr.subcommands;
|
let mut subcommands = aggr.subcommands;
|
||||||
subcommands.extend(directive.subcommands);
|
subcommands.extend(directive.subcommands);
|
||||||
|
let mut notes = aggr.notes;
|
||||||
|
notes.extend(directive.notes);
|
||||||
Ok(Some(Self {
|
Ok(Some(Self {
|
||||||
condition: aggr.condition.or(directive.condition),
|
condition: aggr.condition.or(directive.condition),
|
||||||
subcommands,
|
subcommands,
|
||||||
message: aggr.message.or(directive.message),
|
message: aggr.message.or(directive.message),
|
||||||
label: aggr.label.or(directive.label),
|
label: aggr.label.or(directive.label),
|
||||||
note: aggr.note.or(directive.note),
|
notes,
|
||||||
parent_label: aggr.parent_label.or(directive.parent_label),
|
parent_label: aggr.parent_label.or(directive.parent_label),
|
||||||
append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
|
append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
|
||||||
}))
|
}))
|
||||||
|
@ -543,7 +547,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
value,
|
value,
|
||||||
attr.span,
|
attr.span,
|
||||||
)?),
|
)?),
|
||||||
note: None,
|
notes: Vec::new(),
|
||||||
parent_label: None,
|
parent_label: None,
|
||||||
append_const_msg: None,
|
append_const_msg: None,
|
||||||
}))
|
}))
|
||||||
|
@ -600,7 +604,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
) -> OnUnimplementedNote {
|
) -> OnUnimplementedNote {
|
||||||
let mut message = None;
|
let mut message = None;
|
||||||
let mut label = None;
|
let mut label = None;
|
||||||
let mut note = None;
|
let mut notes = Vec::new();
|
||||||
let mut parent_label = None;
|
let mut parent_label = None;
|
||||||
let mut append_const_msg = None;
|
let mut append_const_msg = None;
|
||||||
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
||||||
|
@ -637,9 +641,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
label = Some(label_.clone());
|
label = Some(label_.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref note_) = command.note {
|
notes.extend(command.notes.clone());
|
||||||
note = Some(note_.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref parent_label_) = command.parent_label {
|
if let Some(ref parent_label_) = command.parent_label {
|
||||||
parent_label = Some(parent_label_.clone());
|
parent_label = Some(parent_label_.clone());
|
||||||
|
@ -651,7 +653,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
OnUnimplementedNote {
|
OnUnimplementedNote {
|
||||||
label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
|
label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
|
||||||
message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
|
message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
|
||||||
note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
|
notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, &options_map)).collect(),
|
||||||
parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
|
parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
|
||||||
append_const_msg,
|
append_const_msg,
|
||||||
}
|
}
|
||||||
|
|
|
@ -445,7 +445,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
let OnUnimplementedNote {
|
let OnUnimplementedNote {
|
||||||
message,
|
message,
|
||||||
label,
|
label,
|
||||||
note,
|
notes,
|
||||||
parent_label,
|
parent_label,
|
||||||
append_const_msg,
|
append_const_msg,
|
||||||
} = self.on_unimplemented_note(trait_ref, &obligation);
|
} = self.on_unimplemented_note(trait_ref, &obligation);
|
||||||
|
@ -453,21 +453,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
|
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
|
||||||
let is_unsize =
|
let is_unsize =
|
||||||
Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
|
Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
|
||||||
let (message, note, append_const_msg) = if is_try_conversion {
|
let (message, notes, append_const_msg) = if is_try_conversion {
|
||||||
(
|
(
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"`?` couldn't convert the error to `{}`",
|
"`?` couldn't convert the error to `{}`",
|
||||||
trait_ref.skip_binder().self_ty(),
|
trait_ref.skip_binder().self_ty(),
|
||||||
)),
|
)),
|
||||||
Some(
|
vec![
|
||||||
"the question mark operation (`?`) implicitly performs a \
|
"the question mark operation (`?`) implicitly performs a \
|
||||||
conversion on the error value using the `From` trait"
|
conversion on the error value using the `From` trait"
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
),
|
],
|
||||||
Some(AppendConstMessage::Default),
|
Some(AppendConstMessage::Default),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(message, note, append_const_msg)
|
(message, notes, append_const_msg)
|
||||||
};
|
};
|
||||||
|
|
||||||
let err_msg = self.get_standard_error_message(
|
let err_msg = self.get_standard_error_message(
|
||||||
|
@ -588,9 +588,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
if let Some((msg, span)) = type_def {
|
if let Some((msg, span)) = type_def {
|
||||||
err.span_label(span, msg);
|
err.span_label(span, msg);
|
||||||
}
|
}
|
||||||
if let Some(s) = note {
|
for note in notes {
|
||||||
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
|
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
|
||||||
err.note(s);
|
err.note(note);
|
||||||
}
|
}
|
||||||
if let Some(s) = parent_label {
|
if let Some(s) = parent_label {
|
||||||
let body = obligation.cause.body_id;
|
let body = obligation.cause.body_id;
|
||||||
|
|
|
@ -154,7 +154,14 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
||||||
|
|
||||||
self.opaques.push(alias_ty.def_id.expect_local());
|
self.opaques.push(alias_ty.def_id.expect_local());
|
||||||
|
|
||||||
match self.tcx.uses_unique_generic_params(alias_ty.args, CheckRegions::Bound) {
|
let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
|
||||||
|
// Only check that the parent generics of the TAIT/RPIT are unique.
|
||||||
|
// the args owned by the opaque are going to always be duplicate
|
||||||
|
// lifetime params for RPITs, and empty for TAITs.
|
||||||
|
match self
|
||||||
|
.tcx
|
||||||
|
.uses_unique_generic_params(&alias_ty.args[..parent_count], CheckRegions::Bound)
|
||||||
|
{
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
// FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
|
// FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
|
||||||
// supported at all, so this is sound to do, but once we want to support them, you'll
|
// supported at all, so this is sound to do, but once we want to support them, you'll
|
||||||
|
|
|
@ -621,7 +621,20 @@ impl<T: ?Sized> Copy for &T {}
|
||||||
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
|
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
|
||||||
),
|
),
|
||||||
on(
|
on(
|
||||||
|
all(
|
||||||
_Self = "core::cell::Cell<T>",
|
_Self = "core::cell::Cell<T>",
|
||||||
|
not(_Self = "core::cell::Cell<u8>"),
|
||||||
|
not(_Self = "core::cell::Cell<u16>"),
|
||||||
|
not(_Self = "core::cell::Cell<u32>"),
|
||||||
|
not(_Self = "core::cell::Cell<u64>"),
|
||||||
|
not(_Self = "core::cell::Cell<usize>"),
|
||||||
|
not(_Self = "core::cell::Cell<i8>"),
|
||||||
|
not(_Self = "core::cell::Cell<i16>"),
|
||||||
|
not(_Self = "core::cell::Cell<i32>"),
|
||||||
|
not(_Self = "core::cell::Cell<i64>"),
|
||||||
|
not(_Self = "core::cell::Cell<isize>"),
|
||||||
|
not(_Self = "core::cell::Cell<bool>")
|
||||||
|
),
|
||||||
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
|
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
|
||||||
),
|
),
|
||||||
on(
|
on(
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
//! Global Allocator for UEFI.
|
//! Global Allocator for UEFI.
|
||||||
//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc)
|
//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc)
|
||||||
|
|
||||||
use crate::alloc::{GlobalAlloc, Layout, System};
|
use r_efi::protocols::loaded_image;
|
||||||
|
|
||||||
const MEMORY_TYPE: u32 = r_efi::efi::LOADER_DATA;
|
use crate::alloc::{GlobalAlloc, Layout, System};
|
||||||
|
use crate::sync::OnceLock;
|
||||||
|
use crate::sys::uefi::helpers;
|
||||||
|
|
||||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||||
unsafe impl GlobalAlloc for System {
|
unsafe impl GlobalAlloc for System {
|
||||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
static EFI_MEMORY_TYPE: OnceLock<u32> = OnceLock::new();
|
||||||
|
|
||||||
// Return null pointer if boot services are not available
|
// Return null pointer if boot services are not available
|
||||||
if crate::os::uefi::env::boot_services().is_none() {
|
if crate::os::uefi::env::boot_services().is_none() {
|
||||||
return crate::ptr::null_mut();
|
return crate::ptr::null_mut();
|
||||||
|
@ -15,8 +19,20 @@ unsafe impl GlobalAlloc for System {
|
||||||
|
|
||||||
// If boot services is valid then SystemTable is not null.
|
// If boot services is valid then SystemTable is not null.
|
||||||
let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
|
let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
|
||||||
|
|
||||||
|
// Each loaded image has an image handle that supports `EFI_LOADED_IMAGE_PROTOCOL`. Thus, this
|
||||||
|
// will never fail.
|
||||||
|
let mem_type = EFI_MEMORY_TYPE.get_or_init(|| {
|
||||||
|
let protocol = helpers::image_handle_protocol::<loaded_image::Protocol>(
|
||||||
|
loaded_image::PROTOCOL_GUID,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
// Gives allocations the memory type that the data sections were loaded as.
|
||||||
|
unsafe { (*protocol.as_ptr()).image_data_type }
|
||||||
|
});
|
||||||
|
|
||||||
// The caller must ensure non-0 layout
|
// The caller must ensure non-0 layout
|
||||||
unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
|
unsafe { r_efi_alloc::raw::alloc(system_table, layout, *mem_type) }
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
// pretty-compare-only
|
||||||
|
// pretty-mode:hir
|
||||||
|
// pp-exact:hir-fn-variadic.pp
|
||||||
|
|
||||||
|
#![feature(c_variadic)]
|
||||||
|
#[prelude_import]
|
||||||
|
use ::std::prelude::rust_2015::*;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn foo(x: i32, va1: ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::<usize>() }
|
|
@ -0,0 +1,13 @@
|
||||||
|
// pretty-compare-only
|
||||||
|
// pretty-mode:hir
|
||||||
|
// pp-exact:hir-fn-variadic.pp
|
||||||
|
|
||||||
|
#![feature(c_variadic)]
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn foo(x: i32, va1: ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize {
|
||||||
|
va2.arg::<usize>()
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ LL | takes_foo(());
|
||||||
|
|
|
|
||||||
= help: the trait `Foo` is not implemented for `()`
|
= help: the trait `Foo` is not implemented for `()`
|
||||||
= note: custom note
|
= note: custom note
|
||||||
|
= note: fallback note
|
||||||
help: this trait has no implementations, consider adding one
|
help: this trait has no implementations, consider adding one
|
||||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1
|
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1
|
||||||
|
|
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#![feature(diagnostic_namespace)]
|
||||||
|
|
||||||
|
#[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz", note = "Boom")]
|
||||||
|
trait Foo {}
|
||||||
|
|
||||||
|
#[diagnostic::on_unimplemented(message = "Bar", label = "Foo", note = "Baz")]
|
||||||
|
#[diagnostic::on_unimplemented(note = "Baz2")]
|
||||||
|
trait Bar {}
|
||||||
|
|
||||||
|
fn takes_foo(_: impl Foo) {}
|
||||||
|
fn takes_bar(_: impl Bar) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
takes_foo(());
|
||||||
|
//~^ERROR Foo
|
||||||
|
takes_bar(());
|
||||||
|
//~^ERROR Bar
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
error[E0277]: Foo
|
||||||
|
--> $DIR/multiple_notes.rs:14:15
|
||||||
|
|
|
||||||
|
LL | takes_foo(());
|
||||||
|
| --------- ^^ Bar
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
= help: the trait `Foo` is not implemented for `()`
|
||||||
|
= note: Baz
|
||||||
|
= note: Boom
|
||||||
|
help: this trait has no implementations, consider adding one
|
||||||
|
--> $DIR/multiple_notes.rs:4:1
|
||||||
|
|
|
||||||
|
LL | trait Foo {}
|
||||||
|
| ^^^^^^^^^
|
||||||
|
note: required by a bound in `takes_foo`
|
||||||
|
--> $DIR/multiple_notes.rs:10:22
|
||||||
|
|
|
||||||
|
LL | fn takes_foo(_: impl Foo) {}
|
||||||
|
| ^^^ required by this bound in `takes_foo`
|
||||||
|
|
||||||
|
error[E0277]: Bar
|
||||||
|
--> $DIR/multiple_notes.rs:16:15
|
||||||
|
|
|
||||||
|
LL | takes_bar(());
|
||||||
|
| --------- ^^ Foo
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
= help: the trait `Bar` is not implemented for `()`
|
||||||
|
= note: Baz
|
||||||
|
= note: Baz2
|
||||||
|
help: this trait has no implementations, consider adding one
|
||||||
|
--> $DIR/multiple_notes.rs:8:1
|
||||||
|
|
|
||||||
|
LL | trait Bar {}
|
||||||
|
| ^^^^^^^^^
|
||||||
|
note: required by a bound in `takes_bar`
|
||||||
|
--> $DIR/multiple_notes.rs:11:22
|
||||||
|
|
|
||||||
|
LL | fn takes_bar(_: impl Bar) {}
|
||||||
|
| ^^^ required by this bound in `takes_bar`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
|
@ -58,6 +58,7 @@ LL | call(foo_unsafe);
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
|
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
|
||||||
|
= note: unsafe function cannot be called generically without an unsafe block
|
||||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
||||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||||
note: required by a bound in `call`
|
note: required by a bound in `call`
|
||||||
|
@ -75,6 +76,7 @@ LL | call_mut(foo_unsafe);
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `FnMut<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
|
= help: the trait `FnMut<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
|
||||||
|
= note: unsafe function cannot be called generically without an unsafe block
|
||||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
||||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||||
note: required by a bound in `call_mut`
|
note: required by a bound in `call_mut`
|
||||||
|
@ -92,6 +94,7 @@ LL | call_once(foo_unsafe);
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `FnOnce<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
|
= help: the trait `FnOnce<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}`
|
||||||
|
= note: unsafe function cannot be called generically without an unsafe block
|
||||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
||||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||||
note: required by a bound in `call_once`
|
note: required by a bound in `call_once`
|
||||||
|
|
|
@ -5,6 +5,7 @@ LL | println!("{}", path);
|
||||||
| ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it
|
| ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it
|
||||||
|
|
|
|
||||||
= help: the trait `std::fmt::Display` is not implemented for `Path`
|
= help: the trait `std::fmt::Display` is not implemented for `Path`
|
||||||
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||||
= note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
|
= note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
|
||||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ LL | println!("{}", path);
|
||||||
| ^^^^ `PathBuf` cannot be formatted with the default formatter; call `.display()` on it
|
| ^^^^ `PathBuf` cannot be formatted with the default formatter; call `.display()` on it
|
||||||
|
|
|
|
||||||
= help: the trait `std::fmt::Display` is not implemented for `PathBuf`
|
= help: the trait `std::fmt::Display` is not implemented for `PathBuf`
|
||||||
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||||
= note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
|
= note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
|
||||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ LL | require_fn(f as unsafe fn() -> i32);
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
|
= help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
|
||||||
|
= note: unsafe function cannot be called generically without an unsafe block
|
||||||
= note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
|
= note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
|
||||||
note: required by a bound in `require_fn`
|
note: required by a bound in `require_fn`
|
||||||
--> $DIR/fn-trait.rs:3:23
|
--> $DIR/fn-trait.rs:3:23
|
||||||
|
@ -97,6 +98,7 @@ LL | require_fn(h);
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}`
|
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}`
|
||||||
|
= note: unsafe function cannot be called generically without an unsafe block
|
||||||
= note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }`
|
= note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }`
|
||||||
note: required by a bound in `require_fn`
|
note: required by a bound in `require_fn`
|
||||||
--> $DIR/fn-trait.rs:3:23
|
--> $DIR/fn-trait.rs:3:23
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
type Opaque<'lt> = impl Sized + 'lt;
|
||||||
|
|
||||||
|
fn test<'a>(
|
||||||
|
arg: impl Iterator<Item = &'a u8>,
|
||||||
|
) -> impl Iterator<Item = Opaque<'a>> {
|
||||||
|
arg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,15 @@
|
||||||
|
// check-pass
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
struct Foo<'a>(&'a ());
|
||||||
|
|
||||||
|
impl<'a> Foo<'a> {
|
||||||
|
async fn new() -> () {
|
||||||
|
type T = impl Sized;
|
||||||
|
let _: T = ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Regression test for issue #114529
|
||||||
|
// Tests that we do not ICE during const eval for a
|
||||||
|
// break-with-value in contexts where it is illegal
|
||||||
|
|
||||||
|
#[allow(while_true)]
|
||||||
|
fn main() {
|
||||||
|
[(); {
|
||||||
|
while true {
|
||||||
|
break 9; //~ ERROR `break` with value from a `while` loop
|
||||||
|
};
|
||||||
|
51
|
||||||
|
}];
|
||||||
|
|
||||||
|
[(); {
|
||||||
|
while let Some(v) = Some(9) {
|
||||||
|
break v; //~ ERROR `break` with value from a `while` loop
|
||||||
|
};
|
||||||
|
51
|
||||||
|
}];
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
error[E0571]: `break` with value from a `while` loop
|
||||||
|
--> $DIR/issue-114529-illegal-break-with-value.rs:9:13
|
||||||
|
|
|
||||||
|
LL | while true {
|
||||||
|
| ---------- you can't `break` with a value in a `while` loop
|
||||||
|
LL | break 9;
|
||||||
|
| ^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
||||||
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
||||||
|
LL | break;
|
||||||
|
| ~~~~~
|
||||||
|
|
||||||
|
error[E0571]: `break` with value from a `while` loop
|
||||||
|
--> $DIR/issue-114529-illegal-break-with-value.rs:16:13
|
||||||
|
|
|
||||||
|
LL | while let Some(v) = Some(9) {
|
||||||
|
| --------------------------- you can't `break` with a value in a `while` loop
|
||||||
|
LL | break v;
|
||||||
|
| ^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
||||||
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
||||||
|
LL | break;
|
||||||
|
| ~~~~~
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0571`.
|
Loading…
Reference in New Issue