Auto merge of #142997 - workingjubilee:rollup-6lxec87, r=workingjubilee
Rollup of 15 pull requests Successful merges: - rust-lang/rust#135731 (Implement parsing of pinned borrows) - rust-lang/rust#138780 (Add `#[loop_match]` for improved DFA codegen) - rust-lang/rust#142453 (Windows: make `read_dir` stop iterating after the first error is encountered) - rust-lang/rust#142633 (Error on invalid signatures for interrupt ABIs) - rust-lang/rust#142768 (Avoid a bitcast FFI call in transmuting) - rust-lang/rust#142825 (Port `#[track_caller]` to the new attribute system) - rust-lang/rust#142844 (Enable short-ice for Windows) - rust-lang/rust#142934 (Tweak `-Zmacro-stats` measurement.) - rust-lang/rust#142955 (Couple of test suite fixes for cg_clif) - rust-lang/rust#142977 (rustdoc: Don't mark `#[target_feature]` functions as ⚠) - rust-lang/rust#142980 (Reduce mismatched-lifetime-syntaxes suggestions to MaybeIncorrect) - rust-lang/rust#142982 (Corrected spelling mistake in c_str.rs) - rust-lang/rust#142983 (Taint body on invalid call ABI) - rust-lang/rust#142988 (Update wasm-component-ld to 0.5.14) - rust-lang/rust#142993 (Update cargo) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a17780db7b
163 changed files with 4230 additions and 430 deletions
54
Cargo.lock
54
Cargo.lock
|
|
@ -3282,6 +3282,7 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3316,6 +3317,7 @@ dependencies = [
|
|||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
|
|
@ -4116,6 +4118,7 @@ dependencies = [
|
|||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -5796,9 +5799,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasi-preview1-component-adapter-provider"
|
||||
version = "31.0.0"
|
||||
version = "34.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86fabda09a0d89ffd1615b297b4a5d4b4d99df9598aeb24685837e63019e927b"
|
||||
checksum = "aafa1e6af9a954a4bcf6ef420c33355d0ce84ddc6afbcba7bb6f05126f9120ae"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
|
|
@ -5860,9 +5863,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-component-ld"
|
||||
version = "0.5.13"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a60a07a994a3538b57d8c5f8caba19f4793fb4c7156276e5e90e90acbb829e20"
|
||||
checksum = "b015ec93764aa5517bc8b839efa9941b90be8ce680b1134f8224644ba1e48e3f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
|
@ -5870,7 +5873,7 @@ dependencies = [
|
|||
"libc",
|
||||
"tempfile",
|
||||
"wasi-preview1-component-adapter-provider",
|
||||
"wasmparser 0.229.0",
|
||||
"wasmparser 0.234.0",
|
||||
"wat",
|
||||
"windows-sys 0.59.0",
|
||||
"winsplit",
|
||||
|
|
@ -5897,12 +5900,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.229.0"
|
||||
version = "0.234.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2"
|
||||
checksum = "170a0157eef517a179f2d20ed7c68df9c3f7f6c1c047782d488bf5a464174684"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.229.0",
|
||||
"wasmparser 0.234.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5917,14 +5920,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.229.0"
|
||||
version = "0.234.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78fdb7d29a79191ab363dc90c1ddd3a1e880ffd5348d92d48482393a9e6c5f4d"
|
||||
checksum = "a42fe3f5cbfb56fc65311ef827930d06189160038e81db62188f66b4bf468e3a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder 0.229.0",
|
||||
"wasmparser 0.229.0",
|
||||
"wasm-encoder 0.234.0",
|
||||
"wasmparser 0.234.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5939,9 +5942,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.229.0"
|
||||
version = "0.234.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c"
|
||||
checksum = "be22e5a8f600afce671dd53c8d2dd26b4b7aa810fd18ae27dfc49737f3e02fc5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"hashbrown",
|
||||
|
|
@ -5950,15 +5953,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.234.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be22e5a8f600afce671dd53c8d2dd26b4b7aa810fd18ae27dfc49737f3e02fc5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.235.0"
|
||||
|
|
@ -6411,9 +6405,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.229.0"
|
||||
version = "0.234.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f550067740e223bfe6c4878998e81cdbe2529dd9a793dc49248dd6613394e8b"
|
||||
checksum = "5a8888169acf4c6c4db535beb405b570eedac13215d6821ca9bd03190f7f8b8c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
|
|
@ -6422,17 +6416,17 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder 0.229.0",
|
||||
"wasm-encoder 0.234.0",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.229.0",
|
||||
"wasmparser 0.234.0",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.229.0"
|
||||
version = "0.234.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "459c6ba62bf511d6b5f2a845a2a736822e38059c1cfa0b644b467bbbfae4efa6"
|
||||
checksum = "465492df47d8dcc015a3b7f241aed8ea03688fee7c5e04162285c5b1a3539c8b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
|
@ -6443,7 +6437,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.229.0",
|
||||
"wasmparser 0.234.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ pub enum ExternAbi {
|
|||
/// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
|
||||
RustCold,
|
||||
|
||||
/// An always-invalid ABI that's used to test "this ABI is not supported by this platform"
|
||||
/// in a platform-agnostic way.
|
||||
RustInvalid,
|
||||
|
||||
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
||||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
|
@ -157,6 +161,7 @@ abi_impls! {
|
|||
RiscvInterruptS =><= "riscv-interrupt-s",
|
||||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustInvalid =><= "rust-invalid",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
|
|
|
|||
|
|
@ -904,6 +904,10 @@ pub enum BorrowKind {
|
|||
/// The resulting type is either `*const T` or `*mut T`
|
||||
/// where `T = typeof($expr)`.
|
||||
Raw,
|
||||
/// A pinned borrow, `&pin const $expr` or `&pin mut $expr`.
|
||||
/// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>`
|
||||
/// where `T = typeof($expr)` and `'a` is some lifetime.
|
||||
Pin,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ doctest = false
|
|||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
|
||||
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::sync::Arc;
|
|||
use rustc_ast::ptr::P as AstP;
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
|
|
@ -831,7 +832,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) {
|
||||
if self.tcx.features().async_fn_track_caller()
|
||||
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
|
||||
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
|
||||
&& find_attr!(*attrs, AttributeKind::TrackCaller(_))
|
||||
{
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
|
|
|
|||
|
|
@ -96,6 +96,9 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
ExternAbi::RustCold => {
|
||||
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
||||
}
|
||||
ExternAbi::RustInvalid => {
|
||||
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
||||
}
|
||||
ExternAbi::GpuKernel => Err(UnstableAbi {
|
||||
abi,
|
||||
feature: sym::abi_gpu_kernel,
|
||||
|
|
|
|||
|
|
@ -18,5 +18,6 @@ rustc_macros = { path = "../rustc_macros" }
|
|||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
thin-vec = "0.2.12"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -1,20 +1,25 @@
|
|||
ast_passes_abi_custom_coroutine =
|
||||
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
|
||||
ast_passes_abi_cannot_be_coroutine =
|
||||
functions with the {$abi} ABI cannot be `{$coroutine_kind_str}`
|
||||
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
|
||||
|
||||
ast_passes_abi_custom_invalid_signature =
|
||||
invalid signature for `extern "custom"` function
|
||||
.note = functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
.suggestion = remove the parameters and return type
|
||||
|
||||
ast_passes_abi_custom_safe_foreign_function =
|
||||
foreign functions with the `"custom"` ABI cannot be safe
|
||||
foreign functions with the "custom" ABI cannot be safe
|
||||
.suggestion = remove the `safe` keyword from this definition
|
||||
|
||||
ast_passes_abi_custom_safe_function =
|
||||
functions with the `"custom"` ABI must be unsafe
|
||||
functions with the "custom" ABI must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
||||
ast_passes_abi_must_not_have_parameters_or_return_type=
|
||||
invalid signature for `extern {$abi}` function
|
||||
.note = functions with the {$abi} ABI cannot have any parameters or return type
|
||||
.suggestion = remove the parameters and return type
|
||||
|
||||
ast_passes_abi_must_not_have_return_type=
|
||||
invalid signature for `extern {$abi}` function
|
||||
.note = functions with the "custom" ABI cannot have a return type
|
||||
.help = remove the return type
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
|
|||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
||||
use rustc_ast::*;
|
||||
|
|
@ -37,6 +37,7 @@ use rustc_session::lint::builtin::{
|
|||
};
|
||||
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use rustc_target::spec::{AbiMap, AbiMapping};
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::errors::{self, TildeConstReason};
|
||||
|
|
@ -365,31 +366,77 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An `extern "custom"` function must be unsafe, and must not have any parameters or return
|
||||
/// type.
|
||||
fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
|
||||
/// Check that the signature of this function does not violate the constraints of its ABI.
|
||||
fn check_extern_fn_signature(&self, abi: ExternAbi, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
|
||||
match AbiMap::from_target(&self.sess.target).canonize_abi(abi, false) {
|
||||
AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => {
|
||||
match canon_abi {
|
||||
CanonAbi::C
|
||||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::GpuKernel
|
||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||
|
||||
CanonAbi::Custom => {
|
||||
// An `extern "custom"` function must be unsafe.
|
||||
self.reject_safe_fn(abi, ctxt, sig);
|
||||
|
||||
// An `extern "custom"` function cannot be `async` and/or `gen`.
|
||||
self.reject_coroutine(abi, sig);
|
||||
|
||||
// An `extern "custom"` function must have type `fn()`.
|
||||
self.reject_params_or_return(abi, ident, sig);
|
||||
}
|
||||
|
||||
CanonAbi::Interrupt(interrupt_kind) => {
|
||||
// An interrupt handler cannot be `async` and/or `gen`.
|
||||
self.reject_coroutine(abi, sig);
|
||||
|
||||
if let InterruptKind::X86 = interrupt_kind {
|
||||
// "x86-interrupt" is special because it does have arguments.
|
||||
// FIXME(workingjubilee): properly lint on acceptable input types.
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
|
||||
self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
|
||||
span: ret_ty.span,
|
||||
abi,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// An `extern "interrupt"` function must have type `fn()`.
|
||||
self.reject_params_or_return(abi, ident, sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AbiMapping::Invalid => { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
fn reject_safe_fn(&self, abi: ExternAbi, ctxt: FnCtxt, sig: &FnSig) {
|
||||
let dcx = self.dcx();
|
||||
|
||||
// An `extern "custom"` function must be unsafe.
|
||||
match sig.header.safety {
|
||||
Safety::Unsafe(_) => { /* all good */ }
|
||||
Safety::Safe(safe_span) => {
|
||||
let safe_span =
|
||||
self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span));
|
||||
let source_map = self.sess.psess.source_map();
|
||||
let safe_span = source_map.span_until_non_whitespace(safe_span.to(sig.span));
|
||||
dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
|
||||
}
|
||||
Safety::Default => match ctxt {
|
||||
FnCtxt::Foreign => { /* all good */ }
|
||||
FnCtxt::Free | FnCtxt::Assoc(_) => {
|
||||
self.dcx().emit_err(errors::AbiCustomSafeFunction {
|
||||
dcx.emit_err(errors::AbiCustomSafeFunction {
|
||||
span: sig.span,
|
||||
abi,
|
||||
unsafe_span: sig.span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// An `extern "custom"` function cannot be `async` and/or `gen`.
|
||||
fn reject_coroutine(&self, abi: ExternAbi, sig: &FnSig) {
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
let coroutine_kind_span = self
|
||||
.sess
|
||||
|
|
@ -397,14 +444,16 @@ impl<'a> AstValidator<'a> {
|
|||
.source_map()
|
||||
.span_until_non_whitespace(coroutine_kind.span().to(sig.span));
|
||||
|
||||
self.dcx().emit_err(errors::AbiCustomCoroutine {
|
||||
self.dcx().emit_err(errors::AbiCannotBeCoroutine {
|
||||
span: sig.span,
|
||||
abi,
|
||||
coroutine_kind_span,
|
||||
coroutine_kind_str: coroutine_kind.as_str(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// An `extern "custom"` function must not have any parameters or return type.
|
||||
fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
|
||||
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
|
||||
spans.push(ret_ty.span);
|
||||
|
|
@ -415,11 +464,12 @@ impl<'a> AstValidator<'a> {
|
|||
let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
|
||||
let padding = if header_span.is_empty() { "" } else { " " };
|
||||
|
||||
self.dcx().emit_err(errors::AbiCustomInvalidSignature {
|
||||
self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType {
|
||||
spans,
|
||||
symbol: ident.name,
|
||||
suggestion_span,
|
||||
padding,
|
||||
abi,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1199,9 +1249,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(sig.header);
|
||||
self.check_foreign_item_ascii_only(*ident);
|
||||
if self.extern_mod_abi == Some(ExternAbi::Custom) {
|
||||
self.check_custom_abi(FnCtxt::Foreign, ident, sig);
|
||||
}
|
||||
self.check_extern_fn_signature(
|
||||
self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK),
|
||||
FnCtxt::Foreign,
|
||||
ident,
|
||||
sig,
|
||||
);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
|
|
@ -1411,9 +1464,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
if let FnKind::Fn(ctxt, _, fun) = fk
|
||||
&& let Extern::Explicit(str_lit, _) = fun.sig.header.ext
|
||||
&& let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str())
|
||||
&& let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str())
|
||||
{
|
||||
self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
|
||||
self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
|
||||
}
|
||||
|
||||
self.check_c_variadic_type(fk);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::ParamKindOrd;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
|
||||
|
|
@ -845,6 +846,7 @@ pub(crate) struct AbiCustomSafeForeignFunction {
|
|||
pub(crate) struct AbiCustomSafeFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub abi: ExternAbi,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
|
|
@ -856,10 +858,11 @@ pub(crate) struct AbiCustomSafeFunction {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_coroutine)]
|
||||
pub(crate) struct AbiCustomCoroutine {
|
||||
#[diag(ast_passes_abi_cannot_be_coroutine)]
|
||||
pub(crate) struct AbiCannotBeCoroutine {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub abi: ExternAbi,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
|
|
@ -872,11 +875,12 @@ pub(crate) struct AbiCustomCoroutine {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_invalid_signature)]
|
||||
#[diag(ast_passes_abi_must_not_have_parameters_or_return_type)]
|
||||
#[note]
|
||||
pub(crate) struct AbiCustomInvalidSignature {
|
||||
pub(crate) struct AbiMustNotHaveParametersOrReturnType {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
pub abi: ExternAbi,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
|
|
@ -888,3 +892,13 @@ pub(crate) struct AbiCustomInvalidSignature {
|
|||
pub symbol: Symbol,
|
||||
pub padding: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_must_not_have_return_type)]
|
||||
#[note]
|
||||
pub(crate) struct AbiMustNotHaveReturnType {
|
||||
#[primary_span]
|
||||
#[help]
|
||||
pub span: Span,
|
||||
pub abi: ExternAbi,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -357,6 +357,10 @@ impl<'a> State<'a> {
|
|||
self.word_nbsp("raw");
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
ast::BorrowKind::Pin => {
|
||||
self.word_nbsp("pin");
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
|
|
|
|||
|
|
@ -212,6 +212,9 @@ pub enum AttributeKind {
|
|||
first_span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[const_continue]`.
|
||||
ConstContinue(Span),
|
||||
|
||||
/// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
|
||||
ConstStability {
|
||||
stability: PartialConstStability,
|
||||
|
|
@ -231,6 +234,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[inline]` and `#[rustc_force_inline]`.
|
||||
Inline(InlineAttr, Span),
|
||||
|
||||
/// Represents `#[loop_match]`.
|
||||
LoopMatch(Span),
|
||||
|
||||
/// Represents `#[rustc_macro_transparency]`.
|
||||
MacroTransparency(Transparency),
|
||||
|
||||
|
|
@ -268,5 +274,8 @@ pub enum AttributeKind {
|
|||
/// Span of the attribute.
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[track_caller]`
|
||||
TrackCaller(Span),
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
|
|
@ -11,7 +11,7 @@ use crate::session_diagnostics::NakedFunctionIncompatibleAttribute;
|
|||
pub(crate) struct OptimizeParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::optimize];
|
||||
const PATH: &[Symbol] = &[sym::optimize];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
|
||||
|
|
@ -44,7 +44,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
|||
pub(crate) struct ColdParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for ColdParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::cold];
|
||||
const PATH: &[Symbol] = &[sym::cold];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
|
@ -166,6 +166,24 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TrackCallerParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for TrackCallerParser {
|
||||
const PATH: &[Symbol] = &[sym::track_caller];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(span);
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::TrackCaller(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct NoMangleParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
|
||||
|
|
|
|||
31
compiler/rustc_attr_parsing/src/attributes/loop_match.rs
Normal file
31
compiler/rustc_attr_parsing/src/attributes/loop_match.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct LoopMatchParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for LoopMatchParser {
|
||||
const PATH: &[Symbol] = &[sym::loop_match];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::LoopMatch(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ConstContinueParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for ConstContinueParser {
|
||||
const PATH: &[Symbol] = &[sym::const_continue];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::ConstContinue(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ pub(crate) mod confusables;
|
|||
pub(crate) mod deprecation;
|
||||
pub(crate) mod inline;
|
||||
pub(crate) mod lint_helpers;
|
||||
pub(crate) mod loop_match;
|
||||
pub(crate) mod must_use;
|
||||
pub(crate) mod repr;
|
||||
pub(crate) mod semantics;
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@ use rustc_session::Session;
|
|||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||
use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser};
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
|
||||
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
|
||||
use crate::attributes::must_use::MustUseParser;
|
||||
use crate::attributes::repr::{AlignParser, ReprParser};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
|
|
@ -111,9 +114,11 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-start
|
||||
Single<AsPtrParser>,
|
||||
Single<ColdParser>,
|
||||
Single<ConstContinueParser>,
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<InlineParser>,
|
||||
Single<LoopMatchParser>,
|
||||
Single<MayDangleParser>,
|
||||
Single<MustUseParser>,
|
||||
Single<NoMangleParser>,
|
||||
|
|
@ -121,6 +126,7 @@ attribute_parsers!(
|
|||
Single<PubTransparentParser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TrackCallerParser>,
|
||||
Single<TransparencyParser>,
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
|
|
|||
|
|
@ -151,20 +151,6 @@ rm tests/ui/process/process-panic-after-fork.rs # same
|
|||
cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist
|
||||
|
||||
cat <<EOF | git apply -
|
||||
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
|
||||
index 30387af428c..f7895b12961 100644
|
||||
--- a/tests/run-make/linker-warning/rmake.rs
|
||||
+++ b/tests/run-make/linker-warning/rmake.rs
|
||||
@@ -57,7 +57,8 @@ fn main() {
|
||||
.actual_text("(linker error)", out.stderr())
|
||||
- .normalize(r#"/rustc[^/]*/"#, "/rustc/")
|
||||
+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/")
|
||||
+ .normalize("libpanic_abort", "libpanic_unwind")
|
||||
.normalize(
|
||||
regex::escape(run_make_support::build_root().to_str().unwrap()),
|
||||
"/build-root",
|
||||
)
|
||||
.normalize(r#""[^"]*\/symbols.o""#, "\\"/symbols.o\\"")
|
||||
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
|
||||
index 073116933bd..c3e4578204d 100644
|
||||
--- a/src/tools/compiletest/src/runtest/run_make.rs
|
||||
|
|
|
|||
|
|
@ -95,17 +95,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// In these cases, we bail from performing further checks that are only meaningful for
|
||||
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
|
||||
// report a delayed bug, just in case `check_attr` isn't doing its job.
|
||||
let fn_sig = || {
|
||||
let fn_sig = |attr_span| {
|
||||
use DefKind::*;
|
||||
|
||||
let def_kind = tcx.def_kind(did);
|
||||
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
|
||||
Some(tcx.fn_sig(did))
|
||||
} else {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
attr.span(),
|
||||
"this attribute can only be applied to functions",
|
||||
);
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(attr_span, "this attribute can only be applied to functions");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
|
@ -142,6 +140,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
});
|
||||
}
|
||||
}
|
||||
AttributeKind::TrackCaller(attr_span) => {
|
||||
let is_closure = tcx.is_closure_like(did.to_def_id());
|
||||
|
||||
if !is_closure
|
||||
&& let Some(fn_sig) = fn_sig(*attr_span)
|
||||
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
|
||||
{
|
||||
tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span });
|
||||
}
|
||||
if is_closure
|
||||
&& !tcx.features().closure_track_caller()
|
||||
&& !attr_span.allows_unstable(sym::closure_track_caller)
|
||||
{
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::closure_track_caller,
|
||||
*attr_span,
|
||||
"`#[track_caller]` on closures is currently unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -202,29 +223,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
||||
sym::track_caller => {
|
||||
let is_closure = tcx.is_closure_like(did.to_def_id());
|
||||
|
||||
if !is_closure
|
||||
&& let Some(fn_sig) = fn_sig()
|
||||
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
|
||||
{
|
||||
tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() });
|
||||
}
|
||||
if is_closure
|
||||
&& !tcx.features().closure_track_caller()
|
||||
&& !attr.span().allows_unstable(sym::closure_track_caller)
|
||||
{
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::closure_track_caller,
|
||||
attr.span(),
|
||||
"`#[track_caller]` on closures is currently unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
|
||||
}
|
||||
sym::export_name => {
|
||||
if let Some(s) = attr.value_str() {
|
||||
if s.as_str().contains('\0') {
|
||||
|
|
|
|||
|
|
@ -1123,7 +1123,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// While optimizations will remove no-op transmutes, they might still be
|
||||
// there in debug or things that aren't no-op in MIR because they change
|
||||
// the Rust type but not the underlying layout/niche.
|
||||
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
|
||||
if from_scalar == to_scalar {
|
||||
return imm;
|
||||
}
|
||||
|
||||
|
|
@ -1142,7 +1142,13 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
|
||||
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => {
|
||||
if from_backend_ty == to_backend_ty {
|
||||
imm
|
||||
} else {
|
||||
bx.bitcast(imm, to_backend_ty)
|
||||
}
|
||||
}
|
||||
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
|
||||
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
|
||||
(Pointer(..), Int(..)) => {
|
||||
|
|
|
|||
|
|
@ -600,11 +600,13 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
|
|||
kind: ccx.const_kind(),
|
||||
teach: ccx.tcx.sess.teach(E0764),
|
||||
}),
|
||||
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
teach: ccx.tcx.sess.teach(E0764),
|
||||
}),
|
||||
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
|
||||
ccx.dcx().create_err(errors::MutableRefEscaping {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
teach: ccx.tcx.sess.teach(E0764),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,15 +15,11 @@ pub struct MacroStat {
|
|||
/// Number of uses of the macro.
|
||||
pub uses: usize,
|
||||
|
||||
/// Net increase in number of lines of code (when pretty-printed), i.e.
|
||||
/// `lines(output) - lines(invocation)`. Can be negative because a macro
|
||||
/// output may be smaller than the invocation.
|
||||
pub lines: isize,
|
||||
/// Number of lines of code (when pretty-printed).
|
||||
pub lines: usize,
|
||||
|
||||
/// Net increase in number of lines of code (when pretty-printed), i.e.
|
||||
/// `bytes(output) - bytes(invocation)`. Can be negative because a macro
|
||||
/// output may be smaller than the invocation.
|
||||
pub bytes: isize,
|
||||
/// Number of bytes of code (when pretty-printed).
|
||||
pub bytes: usize,
|
||||
}
|
||||
|
||||
pub(crate) fn elems_to_string<T>(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> String) -> String {
|
||||
|
|
@ -131,16 +127,12 @@ pub(crate) fn update_macro_stats(
|
|||
input: &str,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
fn lines_and_bytes(s: &str) -> (usize, usize) {
|
||||
(s.trim_end().split('\n').count(), s.len())
|
||||
}
|
||||
|
||||
// Measure the size of the output by pretty-printing it and counting
|
||||
// the lines and bytes.
|
||||
let name = Symbol::intern(&pprust::path_to_string(path));
|
||||
let output = fragment.to_string();
|
||||
let (in_l, in_b) = lines_and_bytes(input);
|
||||
let (out_l, out_b) = lines_and_bytes(&output);
|
||||
let num_lines = output.trim_end().split('\n').count();
|
||||
let num_bytes = output.len();
|
||||
|
||||
// This code is useful for debugging `-Zmacro-stats`. For every
|
||||
// invocation it prints the full input and output.
|
||||
|
|
@ -157,7 +149,7 @@ pub(crate) fn update_macro_stats(
|
|||
{name}: [{crate_name}] ({fragment_kind:?}) {span}\n\
|
||||
-------------------------------\n\
|
||||
{input}\n\
|
||||
-- ({in_l} lines, {in_b} bytes) --> ({out_l} lines, {out_b} bytes) --\n\
|
||||
-- {num_lines} lines, {num_bytes} bytes --\n\
|
||||
{output}\n\
|
||||
"
|
||||
);
|
||||
|
|
@ -166,6 +158,6 @@ pub(crate) fn update_macro_stats(
|
|||
// The recorded size is the difference between the input and the output.
|
||||
let entry = ecx.macro_stats.entry((name, macro_kind)).or_insert(MacroStat::default());
|
||||
entry.uses += 1;
|
||||
entry.lines += out_l as isize - in_l as isize;
|
||||
entry.bytes += out_b as isize - in_b as isize;
|
||||
entry.lines += num_lines;
|
||||
entry.bytes += num_bytes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -657,6 +657,19 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const),
|
||||
),
|
||||
|
||||
// The `#[loop_match]` and `#[const_continue]` attributes are part of the
|
||||
// lang experiment for RFC 3720 tracked in:
|
||||
//
|
||||
// - https://github.com/rust-lang/rust/issues/132306
|
||||
gated!(
|
||||
const_continue, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::No, loop_match, experimental!(const_continue)
|
||||
),
|
||||
gated!(
|
||||
loop_match, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::No, loop_match, experimental!(loop_match)
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes: Stability, deprecation, and unsafe:
|
||||
// ==========================================================================
|
||||
|
|
|
|||
|
|
@ -557,6 +557,8 @@ declare_features! (
|
|||
/// Allows using `#[link(kind = "link-arg", name = "...")]`
|
||||
/// to pass custom arguments to the linker.
|
||||
(unstable, link_arg_attribute, "1.76.0", Some(99427)),
|
||||
/// Allows fused `loop`/`match` for direct intraprocedural jumps.
|
||||
(incomplete, loop_match, "CURRENT_RUSTC_VERSION", Some(132306)),
|
||||
/// Give access to additional metadata about declarative macro meta-variables.
|
||||
(unstable, macro_metavar_expr, "1.61.0", Some(83527)),
|
||||
/// Provides a way to concatenate identifiers using metavariable expressions.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
hir_analysis_abi_custom_clothed_function =
|
||||
items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
.suggestion = convert this to an `#[unsafe(naked)]` function
|
||||
|
||||
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use std::ops::Not;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::Node;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypingMode};
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
|
||||
|
|
@ -98,8 +99,10 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
|||
error = true;
|
||||
}
|
||||
|
||||
for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
|
||||
tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span });
|
||||
if let Some(attr_span) =
|
||||
find_attr!(tcx.get_all_attrs(main_def_id), AttributeKind::TrackCaller(span) => *span)
|
||||
{
|
||||
tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span });
|
||||
error = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1335,6 +1335,10 @@ impl<'a> State<'a> {
|
|||
self.word_nbsp("raw");
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
hir::BorrowKind::Pin => {
|
||||
self.word_nbsp("pin");
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ hir_typeck_cast_unknown_pointer = cannot cast {$to ->
|
|||
.note = the type information given here is insufficient to check whether the pointer cast is valid
|
||||
.label_from = the type information given here is insufficient to check whether the pointer cast is valid
|
||||
|
||||
hir_typeck_const_continue_bad_label =
|
||||
`#[const_continue]` must break to a labeled block that participates in a `#[loop_match]`
|
||||
|
||||
hir_typeck_const_select_must_be_const = this argument must be a `const fn`
|
||||
.help = consult the documentation on `const_eval_select` for more information
|
||||
|
||||
|
|
|
|||
|
|
@ -156,7 +156,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub(crate) fn check_call_abi(&self, abi: ExternAbi, span: Span) {
|
||||
let canon_abi = match AbiMap::from_target(&self.sess().target).canonize_abi(abi, false) {
|
||||
AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => canon_abi,
|
||||
AbiMapping::Invalid => return,
|
||||
AbiMapping::Invalid => {
|
||||
// This should be reported elsewhere, but we want to taint this body
|
||||
// so that we don't try to evaluate calls to ABIs that are invalid.
|
||||
let guar = self.dcx().span_delayed_bug(
|
||||
span,
|
||||
format!("invalid abi for platform should have reported an error: {abi}"),
|
||||
);
|
||||
self.set_tainted_by_errors(guar);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let valid = match canon_abi {
|
||||
|
|
|
|||
|
|
@ -1167,3 +1167,10 @@ pub(crate) struct AbiCannotBeCalled {
|
|||
pub span: Span,
|
||||
pub abi: ExternAbi,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_const_continue_bad_label)]
|
||||
pub(crate) struct ConstContinueBadLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.check_named_place_expr(oprnd);
|
||||
Ty::new_ptr(self.tcx, ty, mutbl)
|
||||
}
|
||||
hir::BorrowKind::Ref => {
|
||||
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
|
||||
// Note: at this point, we cannot say what the best lifetime
|
||||
// is to use for resulting pointer. We want to use the
|
||||
// shortest lifetime possible so as to avoid spurious borrowck
|
||||
|
|
@ -706,7 +706,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// whose address was taken can actually be made to live as long
|
||||
// as it needs to live.
|
||||
let region = self.next_region_var(infer::BorrowRegion(expr.span));
|
||||
Ty::new_ref(self.tcx, region, ty, mutbl)
|
||||
match kind {
|
||||
hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl),
|
||||
hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use std::collections::BTreeMap;
|
|||
use std::fmt;
|
||||
|
||||
use Context::*;
|
||||
use rustc_ast::Label;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
|
@ -14,8 +16,9 @@ use rustc_span::hygiene::DesugaringKind;
|
|||
use rustc_span::{BytePos, Span};
|
||||
|
||||
use crate::errors::{
|
||||
BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
|
||||
OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
|
||||
BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ConstContinueBadLabel,
|
||||
ContinueLabeledBlock, OutsideLoop, OutsideLoopSuggestion, UnlabeledCfInWhileCondition,
|
||||
UnlabeledInLabeledBlock,
|
||||
};
|
||||
|
||||
/// The context in which a block is encountered.
|
||||
|
|
@ -37,6 +40,11 @@ enum Context {
|
|||
AnonConst,
|
||||
/// E.g. `const { ... }`.
|
||||
ConstBlock,
|
||||
/// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`.
|
||||
LoopMatch {
|
||||
/// The label of the labeled block (not of the loop itself).
|
||||
labeled_block: Label,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -141,7 +149,12 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
|
|||
}
|
||||
}
|
||||
hir::ExprKind::Loop(ref b, _, source, _) => {
|
||||
self.with_context(Loop(source), |v| v.visit_block(b));
|
||||
let cx = match self.is_loop_match(e, b) {
|
||||
Some(labeled_block) => LoopMatch { labeled_block },
|
||||
None => Loop(source),
|
||||
};
|
||||
|
||||
self.with_context(cx, |v| v.visit_block(b));
|
||||
}
|
||||
hir::ExprKind::Closure(&hir::Closure {
|
||||
ref fn_decl, body, fn_decl_span, kind, ..
|
||||
|
|
@ -197,6 +210,23 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
|
|||
Err(hir::LoopIdError::UnresolvedLabel) => None,
|
||||
};
|
||||
|
||||
// A `#[const_continue]` must break to a block in a `#[loop_match]`.
|
||||
if find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::ConstContinue(_)) {
|
||||
if let Some(break_label) = break_label.label {
|
||||
let is_target_label = |cx: &Context| match cx {
|
||||
Context::LoopMatch { labeled_block } => {
|
||||
break_label.ident.name == labeled_block.ident.name
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !self.cx_stack.iter().rev().any(is_target_label) {
|
||||
let span = break_label.ident.span;
|
||||
self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Node::Block(_)) = loop_id.map(|id| self.tcx.hir_node(id)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -299,7 +329,7 @@ impl<'hir> CheckLoopVisitor<'hir> {
|
|||
cx_pos: usize,
|
||||
) {
|
||||
match self.cx_stack[cx_pos] {
|
||||
LabeledBlock | Loop(_) => {}
|
||||
LabeledBlock | Loop(_) | LoopMatch { .. } => {}
|
||||
Closure(closure_span) => {
|
||||
self.tcx.dcx().emit_err(BreakInsideClosure {
|
||||
span,
|
||||
|
|
@ -380,4 +410,36 @@ impl<'hir> CheckLoopVisitor<'hir> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this a loop annotated with `#[loop_match]` that looks syntactically sound?
|
||||
fn is_loop_match(
|
||||
&self,
|
||||
e: &'hir hir::Expr<'hir>,
|
||||
body: &'hir hir::Block<'hir>,
|
||||
) -> Option<Label> {
|
||||
if !find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::LoopMatch(_)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// NOTE: Diagnostics are emitted during MIR construction.
|
||||
|
||||
// Accept either `state = expr` or `state = expr;`.
|
||||
let loop_body_expr = match body.stmts {
|
||||
[] => match body.expr {
|
||||
Some(expr) => expr,
|
||||
None => return None,
|
||||
},
|
||||
[single] if body.expr.is_none() => match single.kind {
|
||||
hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => expr,
|
||||
_ => return None,
|
||||
},
|
||||
[..] => return None,
|
||||
};
|
||||
|
||||
let hir::ExprKind::Assign(_, rhs_expr, _) = loop_body_expr.kind else { return None };
|
||||
|
||||
let hir::ExprKind::Block(_, label) = rhs_expr.kind else { return None };
|
||||
|
||||
label
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -355,9 +355,9 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) {
|
|||
"{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
|
||||
name,
|
||||
thousands::usize_with_underscores(uses),
|
||||
thousands::isize_with_underscores(lines),
|
||||
thousands::usize_with_underscores(lines),
|
||||
thousands::f64p1_with_underscores(avg_lines),
|
||||
thousands::isize_with_underscores(bytes),
|
||||
thousands::usize_with_underscores(bytes),
|
||||
thousands::f64p1_with_underscores(avg_bytes),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1184,11 +1184,11 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
|
|||
if fn_kind.asyncness().is_async()
|
||||
&& !cx.tcx.features().async_fn_track_caller()
|
||||
// Now, check if the function has the `#[track_caller]` attribute
|
||||
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
|
||||
&& let Some(attr_span) = find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::TrackCaller(span) => *span)
|
||||
{
|
||||
cx.emit_span_lint(
|
||||
UNGATED_ASYNC_FN_TRACK_CALLER,
|
||||
attr.span(),
|
||||
attr_span,
|
||||
BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3278,7 +3278,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
|
|||
diag.multipart_suggestion_with_style(
|
||||
fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
Applicability::MaybeIncorrect,
|
||||
style(tool_only),
|
||||
);
|
||||
}
|
||||
|
|
@ -3293,7 +3293,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
|
|||
diag.multipart_suggestion_with_style(
|
||||
fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
Applicability::MaybeIncorrect,
|
||||
style(tool_only),
|
||||
);
|
||||
}
|
||||
|
|
@ -3308,7 +3308,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
|
|||
diag.multipart_suggestion_with_style(
|
||||
msg,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
Applicability::MaybeIncorrect,
|
||||
style(tool_only),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -378,6 +378,14 @@ pub enum ExprKind<'tcx> {
|
|||
Loop {
|
||||
body: ExprId,
|
||||
},
|
||||
/// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression.
|
||||
LoopMatch {
|
||||
/// The state variable that is updated, and also the scrutinee of the match.
|
||||
state: ExprId,
|
||||
region_scope: region::Scope,
|
||||
arms: Box<[ArmId]>,
|
||||
match_span: Span,
|
||||
},
|
||||
/// Special expression representing the `let` part of an `if let` or similar construct
|
||||
/// (including `if let` guards in match arms, and let-chains formed by `&&`).
|
||||
///
|
||||
|
|
@ -454,6 +462,11 @@ pub enum ExprKind<'tcx> {
|
|||
Continue {
|
||||
label: region::Scope,
|
||||
},
|
||||
/// A `#[const_continue] break` expression.
|
||||
ConstContinue {
|
||||
label: region::Scope,
|
||||
value: ExprId,
|
||||
},
|
||||
/// A `return` expression.
|
||||
Return {
|
||||
value: Option<ExprId>,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
visitor.visit_pat(pat);
|
||||
}
|
||||
Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
|
||||
Match { scrutinee, ref arms, .. } => {
|
||||
LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => {
|
||||
visitor.visit_expr(&visitor.thir()[scrutinee]);
|
||||
for &arm in &**arms {
|
||||
visitor.visit_arm(&visitor.thir()[arm]);
|
||||
|
|
@ -108,6 +108,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
}
|
||||
}
|
||||
Continue { label: _ } => {}
|
||||
ConstContinue { value, label: _ } => visitor.visit_expr(&visitor.thir()[value]),
|
||||
Return { value } => {
|
||||
if let Some(value) = value {
|
||||
visitor.visit_expr(&visitor.thir()[value])
|
||||
|
|
|
|||
|
|
@ -1253,7 +1253,8 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
|
|||
| CCmseNonSecureCall
|
||||
| CCmseNonSecureEntry
|
||||
| Custom
|
||||
| Unadjusted => false,
|
||||
| Unadjusted
|
||||
| RustInvalid => false,
|
||||
Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ rustc_abi = { path = "../rustc_abi" }
|
|||
rustc_apfloat = "0.2.0"
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
|
|
|
|||
|
|
@ -84,6 +84,15 @@ mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
|||
|
||||
mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
|
||||
|
||||
mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]`
|
||||
.label = this value is too generic
|
||||
.note = the value must be a literal or a monomorphic const
|
||||
|
||||
mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value
|
||||
|
||||
mir_build_const_continue_unknown_jump_target = the target of this `#[const_continue]` is not statically known
|
||||
.label = this value must be a literal or a monomorphic const
|
||||
|
||||
mir_build_const_defined_here = constant defined here
|
||||
|
||||
mir_build_const_param_in_pattern = constant parameters cannot be referenced in patterns
|
||||
|
|
@ -212,6 +221,30 @@ mir_build_literal_in_range_out_of_bounds =
|
|||
literal out of range for `{$ty}`
|
||||
.label = this value does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
|
||||
|
||||
mir_build_loop_match_arm_with_guard =
|
||||
match arms that are part of a `#[loop_match]` cannot have guards
|
||||
|
||||
mir_build_loop_match_bad_rhs =
|
||||
this expression must be a single `match` wrapped in a labeled block
|
||||
|
||||
mir_build_loop_match_bad_statements =
|
||||
statements are not allowed in this position within a `#[loop_match]`
|
||||
|
||||
mir_build_loop_match_invalid_match =
|
||||
invalid match on `#[loop_match]` state
|
||||
.note = a local variable must be the scrutinee within a `#[loop_match]`
|
||||
|
||||
mir_build_loop_match_invalid_update =
|
||||
invalid update of the `#[loop_match]` state
|
||||
.label = the assignment must update this variable
|
||||
|
||||
mir_build_loop_match_missing_assignment =
|
||||
expected a single assignment expression
|
||||
|
||||
mir_build_loop_match_unsupported_type =
|
||||
this `#[loop_match]` state value has type `{$ty}`, which is not supported
|
||||
.note = only integers, floats, bool, char, and enums without fields are supported
|
||||
|
||||
mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
|
||||
lower range bound must be less than or equal to upper
|
||||
.label = lower bound larger than upper bound
|
||||
|
|
|
|||
|
|
@ -565,12 +565,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| ExprKind::Match { .. }
|
||||
| ExprKind::If { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::LoopMatch { .. }
|
||||
| ExprKind::Block { .. }
|
||||
| ExprKind::Let { .. }
|
||||
| ExprKind::Assign { .. }
|
||||
| ExprKind::AssignOp { .. }
|
||||
| ExprKind::Break { .. }
|
||||
| ExprKind::Continue { .. }
|
||||
| ExprKind::ConstContinue { .. }
|
||||
| ExprKind::Return { .. }
|
||||
| ExprKind::Become { .. }
|
||||
| ExprKind::Literal { .. }
|
||||
|
|
|
|||
|
|
@ -538,6 +538,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| ExprKind::RawBorrow { .. }
|
||||
| ExprKind::Adt { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::LoopMatch { .. }
|
||||
| ExprKind::LogicalOp { .. }
|
||||
| ExprKind::Call { .. }
|
||||
| ExprKind::Field { .. }
|
||||
|
|
@ -548,6 +549,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| ExprKind::UpvarRef { .. }
|
||||
| ExprKind::Break { .. }
|
||||
| ExprKind::Continue { .. }
|
||||
| ExprKind::ConstContinue { .. }
|
||||
| ExprKind::Return { .. }
|
||||
| ExprKind::Become { .. }
|
||||
| ExprKind::InlineAsm { .. }
|
||||
|
|
|
|||
|
|
@ -83,9 +83,11 @@ impl Category {
|
|||
| ExprKind::NamedConst { .. } => Some(Category::Constant),
|
||||
|
||||
ExprKind::Loop { .. }
|
||||
| ExprKind::LoopMatch { .. }
|
||||
| ExprKind::Block { .. }
|
||||
| ExprKind::Break { .. }
|
||||
| ExprKind::Continue { .. }
|
||||
| ExprKind::ConstContinue { .. }
|
||||
| ExprKind::Return { .. }
|
||||
| ExprKind::Become { .. } =>
|
||||
// FIXME(#27840) these probably want their own
|
||||
|
|
|
|||
|
|
@ -8,15 +8,16 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_middle::mir::*;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::builder::expr::category::{Category, RvalueFunc};
|
||||
use crate::builder::matches::DeclareLetBindings;
|
||||
use crate::builder::matches::{DeclareLetBindings, HasMatchGuard};
|
||||
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
|
||||
use crate::errors::{LoopMatchArmWithGuard, LoopMatchUnsupportedType};
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// Compile `expr`, storing the result into `destination`, which
|
||||
|
|
@ -244,6 +245,122 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
None
|
||||
})
|
||||
}
|
||||
ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => {
|
||||
// Intuitively, this is a combination of a loop containing a labeled block
|
||||
// containing a match.
|
||||
//
|
||||
// The only new bit here is that the lowering of the match is wrapped in a
|
||||
// `in_const_continuable_scope`, which makes the match arms and their target basic
|
||||
// block available to the lowering of `#[const_continue]`.
|
||||
|
||||
fn is_supported_loop_match_type(ty: Ty<'_>) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Bool | ty::Char => true,
|
||||
ty::Adt(adt_def, _) => match adt_def.adt_kind() {
|
||||
ty::AdtKind::Struct | ty::AdtKind::Union => false,
|
||||
ty::AdtKind::Enum => {
|
||||
adt_def.variants().iter().all(|v| v.fields.is_empty())
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
let state_ty = this.thir.exprs[state].ty;
|
||||
if !is_supported_loop_match_type(state_ty) {
|
||||
let span = this.thir.exprs[state].span;
|
||||
this.tcx.dcx().emit_fatal(LoopMatchUnsupportedType { span, ty: state_ty })
|
||||
}
|
||||
|
||||
let loop_block = this.cfg.start_new_block();
|
||||
|
||||
// Start the loop.
|
||||
this.cfg.goto(block, source_info, loop_block);
|
||||
|
||||
this.in_breakable_scope(Some(loop_block), destination, expr_span, |this| {
|
||||
// Logic for `loop`.
|
||||
let mut body_block = this.cfg.start_new_block();
|
||||
this.cfg.terminate(
|
||||
loop_block,
|
||||
source_info,
|
||||
TerminatorKind::FalseUnwind {
|
||||
real_target: body_block,
|
||||
unwind: UnwindAction::Continue,
|
||||
},
|
||||
);
|
||||
this.diverge_from(loop_block);
|
||||
|
||||
// Logic for `match`.
|
||||
let scrutinee_place_builder =
|
||||
unpack!(body_block = this.as_place_builder(body_block, state));
|
||||
let scrutinee_span = this.thir.exprs[state].span;
|
||||
let match_start_span = match_span.shrink_to_lo().to(scrutinee_span);
|
||||
|
||||
let mut patterns = Vec::with_capacity(arms.len());
|
||||
for &arm_id in arms.iter() {
|
||||
let arm = &this.thir[arm_id];
|
||||
|
||||
if let Some(guard) = arm.guard {
|
||||
let span = this.thir.exprs[guard].span;
|
||||
this.tcx.dcx().emit_fatal(LoopMatchArmWithGuard { span })
|
||||
}
|
||||
|
||||
patterns.push((&*arm.pattern, HasMatchGuard::No));
|
||||
}
|
||||
|
||||
// The `built_tree` maps match arms to their basic block (where control flow
|
||||
// jumps to when a value matches the arm). This structure is stored so that a
|
||||
// `#[const_continue]` can figure out what basic block to jump to.
|
||||
let built_tree = this.lower_match_tree(
|
||||
body_block,
|
||||
scrutinee_span,
|
||||
&scrutinee_place_builder,
|
||||
match_start_span,
|
||||
patterns,
|
||||
false,
|
||||
);
|
||||
|
||||
let state_place = scrutinee_place_builder.to_place(this);
|
||||
|
||||
// This is logic for the labeled block: a block is a drop scope, hence
|
||||
// `in_scope`, and a labeled block can be broken out of with a `break 'label`,
|
||||
// hence the `in_breakable_scope`.
|
||||
//
|
||||
// Then `in_const_continuable_scope` stores information for the lowering of
|
||||
// `#[const_continue]`, and finally the match is lowered in the standard way.
|
||||
unpack!(
|
||||
body_block = this.in_scope(
|
||||
(region_scope, source_info),
|
||||
LintLevel::Inherited,
|
||||
move |this| {
|
||||
this.in_breakable_scope(None, state_place, expr_span, |this| {
|
||||
Some(this.in_const_continuable_scope(
|
||||
arms.clone(),
|
||||
built_tree.clone(),
|
||||
state_place,
|
||||
expr_span,
|
||||
|this| {
|
||||
this.lower_match_arms(
|
||||
destination,
|
||||
scrutinee_place_builder,
|
||||
scrutinee_span,
|
||||
arms,
|
||||
built_tree,
|
||||
this.source_info(match_span),
|
||||
)
|
||||
},
|
||||
))
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
this.cfg.goto(body_block, source_info, loop_block);
|
||||
|
||||
// Loops are only exited by `break` expressions.
|
||||
None
|
||||
})
|
||||
}
|
||||
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
|
||||
let fun = unpack!(block = this.as_local_operand(block, fun));
|
||||
let args: Box<[_]> = args
|
||||
|
|
@ -601,6 +718,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ExprKind::Continue { .. }
|
||||
| ExprKind::ConstContinue { .. }
|
||||
| ExprKind::Break { .. }
|
||||
| ExprKind::Return { .. }
|
||||
| ExprKind::Become { .. } => {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
ExprKind::Break { label, value } => {
|
||||
this.break_scope(block, value, BreakableTarget::Break(label), source_info)
|
||||
}
|
||||
ExprKind::ConstContinue { label, value } => {
|
||||
this.break_const_continuable_scope(block, value, label, source_info)
|
||||
}
|
||||
ExprKind::Return { value } => {
|
||||
this.break_scope(block, value, BreakableTarget::Return, source_info)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ use rustc_middle::bug;
|
|||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::{self, *};
|
||||
use rustc_middle::thir::{self, *};
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind};
|
||||
use rustc_pattern_analysis::constructor::RangeEnd;
|
||||
use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt};
|
||||
use rustc_span::{BytePos, Pos, Span, Symbol, sym};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -426,7 +428,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
/// (by [Builder::lower_match_tree]).
|
||||
///
|
||||
/// `outer_source_info` is the SourceInfo for the whole match.
|
||||
fn lower_match_arms(
|
||||
pub(crate) fn lower_match_arms(
|
||||
&mut self,
|
||||
destination: Place<'tcx>,
|
||||
scrutinee_place_builder: PlaceBuilder<'tcx>,
|
||||
|
|
@ -1395,7 +1397,7 @@ pub(crate) struct ArmHasGuard(pub(crate) bool);
|
|||
/// A sub-branch in the output of match lowering. Match lowering has generated MIR code that will
|
||||
/// branch to `success_block` when the matched value matches the corresponding pattern. If there is
|
||||
/// a guard, its failure must continue to `otherwise_block`, which will resume testing patterns.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct MatchTreeSubBranch<'tcx> {
|
||||
span: Span,
|
||||
/// The block that is branched to if the corresponding subpattern matches.
|
||||
|
|
@ -1411,7 +1413,7 @@ struct MatchTreeSubBranch<'tcx> {
|
|||
}
|
||||
|
||||
/// A branch in the output of match lowering.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct MatchTreeBranch<'tcx> {
|
||||
sub_branches: Vec<MatchTreeSubBranch<'tcx>>,
|
||||
}
|
||||
|
|
@ -1430,8 +1432,8 @@ struct MatchTreeBranch<'tcx> {
|
|||
/// Here the first arm gives the first `MatchTreeBranch`, which has two sub-branches, one for each
|
||||
/// alternative of the or-pattern. They are kept separate because each needs to bind `x` to a
|
||||
/// different place.
|
||||
#[derive(Debug)]
|
||||
struct BuiltMatchTree<'tcx> {
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct BuiltMatchTree<'tcx> {
|
||||
branches: Vec<MatchTreeBranch<'tcx>>,
|
||||
otherwise_block: BasicBlock,
|
||||
/// If any of the branches had a guard, we collect here the places and locals to fakely borrow
|
||||
|
|
@ -1489,7 +1491,7 @@ impl<'tcx> MatchTreeBranch<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum HasMatchGuard {
|
||||
pub(crate) enum HasMatchGuard {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
|
@ -1504,7 +1506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
/// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
|
||||
/// or not (for `let` and `match`). In the refutable case we return the block to which we branch
|
||||
/// on failure.
|
||||
fn lower_match_tree(
|
||||
pub(crate) fn lower_match_tree(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
scrutinee_span: Span,
|
||||
|
|
@ -1890,7 +1892,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
|
||||
candidate.or_span = Some(match_pair.pattern_span);
|
||||
candidate.subcandidates = pats
|
||||
.into_vec()
|
||||
.into_iter()
|
||||
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
|
||||
.collect();
|
||||
|
|
@ -2864,4 +2865,129 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
/// Attempt to statically pick the `BasicBlock` that a value would resolve to at runtime.
|
||||
pub(crate) fn static_pattern_match(
|
||||
&self,
|
||||
cx: &RustcPatCtxt<'_, 'tcx>,
|
||||
valtree: ValTree<'tcx>,
|
||||
arms: &[ArmId],
|
||||
built_match_tree: &BuiltMatchTree<'tcx>,
|
||||
) -> Option<BasicBlock> {
|
||||
let it = arms.iter().zip(built_match_tree.branches.iter());
|
||||
for (&arm_id, branch) in it {
|
||||
let pat = cx.lower_pat(&*self.thir.arms[arm_id].pattern);
|
||||
|
||||
// Peel off or-patterns if they exist.
|
||||
if let rustc_pattern_analysis::rustc::Constructor::Or = pat.ctor() {
|
||||
for pat in pat.iter_fields() {
|
||||
// For top-level or-patterns (the only ones we accept right now), when the
|
||||
// bindings are the same (e.g. there are none), the sub_branch is stored just
|
||||
// once.
|
||||
let sub_branch = branch
|
||||
.sub_branches
|
||||
.get(pat.idx)
|
||||
.or_else(|| branch.sub_branches.last())
|
||||
.unwrap();
|
||||
|
||||
match self.static_pattern_match_inner(valtree, &pat.pat) {
|
||||
true => return Some(sub_branch.success_block),
|
||||
false => continue,
|
||||
}
|
||||
}
|
||||
} else if self.static_pattern_match_inner(valtree, &pat) {
|
||||
return Some(branch.sub_branches[0].success_block);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Helper for [`Self::static_pattern_match`], checking whether the value represented by the
|
||||
/// `ValTree` matches the given pattern. This function does not recurse, meaning that it does
|
||||
/// not handle or-patterns, or patterns for types with fields.
|
||||
fn static_pattern_match_inner(
|
||||
&self,
|
||||
valtree: ty::ValTree<'tcx>,
|
||||
pat: &DeconstructedPat<'_, 'tcx>,
|
||||
) -> bool {
|
||||
use rustc_pattern_analysis::constructor::{IntRange, MaybeInfiniteInt};
|
||||
use rustc_pattern_analysis::rustc::Constructor;
|
||||
|
||||
match pat.ctor() {
|
||||
Constructor::Variant(variant_index) => {
|
||||
let ValTreeKind::Branch(box [actual_variant_idx]) = *valtree else {
|
||||
bug!("malformed valtree for an enum")
|
||||
};
|
||||
|
||||
let ValTreeKind::Leaf(actual_variant_idx) = ***actual_variant_idx else {
|
||||
bug!("malformed valtree for an enum")
|
||||
};
|
||||
|
||||
*variant_index == VariantIdx::from_u32(actual_variant_idx.to_u32())
|
||||
}
|
||||
Constructor::IntRange(int_range) => {
|
||||
let size = pat.ty().primitive_size(self.tcx);
|
||||
let actual_int = valtree.unwrap_leaf().to_bits(size);
|
||||
let actual_int = if pat.ty().is_signed() {
|
||||
MaybeInfiniteInt::new_finite_int(actual_int, size.bits())
|
||||
} else {
|
||||
MaybeInfiniteInt::new_finite_uint(actual_int)
|
||||
};
|
||||
IntRange::from_singleton(actual_int).is_subrange(int_range)
|
||||
}
|
||||
Constructor::Bool(pattern_value) => match valtree.unwrap_leaf().try_to_bool() {
|
||||
Ok(actual_value) => *pattern_value == actual_value,
|
||||
Err(()) => bug!("bool value with invalid bits"),
|
||||
},
|
||||
Constructor::F16Range(l, h, end) => {
|
||||
let actual = valtree.unwrap_leaf().to_f16();
|
||||
match end {
|
||||
RangeEnd::Included => (*l..=*h).contains(&actual),
|
||||
RangeEnd::Excluded => (*l..*h).contains(&actual),
|
||||
}
|
||||
}
|
||||
Constructor::F32Range(l, h, end) => {
|
||||
let actual = valtree.unwrap_leaf().to_f32();
|
||||
match end {
|
||||
RangeEnd::Included => (*l..=*h).contains(&actual),
|
||||
RangeEnd::Excluded => (*l..*h).contains(&actual),
|
||||
}
|
||||
}
|
||||
Constructor::F64Range(l, h, end) => {
|
||||
let actual = valtree.unwrap_leaf().to_f64();
|
||||
match end {
|
||||
RangeEnd::Included => (*l..=*h).contains(&actual),
|
||||
RangeEnd::Excluded => (*l..*h).contains(&actual),
|
||||
}
|
||||
}
|
||||
Constructor::F128Range(l, h, end) => {
|
||||
let actual = valtree.unwrap_leaf().to_f128();
|
||||
match end {
|
||||
RangeEnd::Included => (*l..=*h).contains(&actual),
|
||||
RangeEnd::Excluded => (*l..*h).contains(&actual),
|
||||
}
|
||||
}
|
||||
Constructor::Wildcard => true,
|
||||
|
||||
// These we may eventually support:
|
||||
Constructor::Struct
|
||||
| Constructor::Ref
|
||||
| Constructor::DerefPattern(_)
|
||||
| Constructor::Slice(_)
|
||||
| Constructor::UnionField
|
||||
| Constructor::Or
|
||||
| Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()),
|
||||
|
||||
// These should never occur here:
|
||||
Constructor::Opaque(_)
|
||||
| Constructor::Never
|
||||
| Constructor::NonExhaustive
|
||||
| Constructor::Hidden
|
||||
| Constructor::Missing
|
||||
| Constructor::PrivateUninhabited => {
|
||||
bug!("unsupported pattern constructor {:?}", pat.ctor())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,20 +83,24 @@ that contains only loops and breakable blocks. It tracks where a `break`,
|
|||
|
||||
use std::mem;
|
||||
|
||||
use interpret::ErrorHandled;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::{ExprId, LintLevel};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::mir::{self, *};
|
||||
use rustc_middle::thir::{AdtExpr, AdtExprBase, ArmId, ExprId, ExprKind, LintLevel};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_pattern_analysis::rustc::RustcPatCtxt;
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::matches::BuiltMatchTree;
|
||||
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
|
||||
use crate::errors::{ConstContinueBadConst, ConstContinueUnknownJumpTarget};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Scopes<'tcx> {
|
||||
|
|
@ -105,6 +109,8 @@ pub(crate) struct Scopes<'tcx> {
|
|||
/// The current set of breakable scopes. See module comment for more details.
|
||||
breakable_scopes: Vec<BreakableScope<'tcx>>,
|
||||
|
||||
const_continuable_scopes: Vec<ConstContinuableScope<'tcx>>,
|
||||
|
||||
/// The scope of the innermost if-then currently being lowered.
|
||||
if_then_scope: Option<IfThenScope>,
|
||||
|
||||
|
|
@ -174,6 +180,20 @@ struct BreakableScope<'tcx> {
|
|||
continue_drops: Option<DropTree>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ConstContinuableScope<'tcx> {
|
||||
/// The scope for the `#[loop_match]` which its `#[const_continue]`s will jump to.
|
||||
region_scope: region::Scope,
|
||||
/// The place of the state of a `#[loop_match]`, which a `#[const_continue]` must update.
|
||||
state_place: Place<'tcx>,
|
||||
|
||||
arms: Box<[ArmId]>,
|
||||
built_match_tree: BuiltMatchTree<'tcx>,
|
||||
|
||||
/// Drops that happen on a `#[const_continue]`
|
||||
const_continue_drops: DropTree,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct IfThenScope {
|
||||
/// The if-then scope or arm scope
|
||||
|
|
@ -461,6 +481,7 @@ impl<'tcx> Scopes<'tcx> {
|
|||
Self {
|
||||
scopes: Vec::new(),
|
||||
breakable_scopes: Vec::new(),
|
||||
const_continuable_scopes: Vec::new(),
|
||||
if_then_scope: None,
|
||||
unwind_drops: DropTree::new(),
|
||||
coroutine_drops: DropTree::new(),
|
||||
|
|
@ -552,6 +573,59 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Start a const-continuable scope, which tracks where `#[const_continue] break` should
|
||||
/// branch to.
|
||||
pub(crate) fn in_const_continuable_scope<F>(
|
||||
&mut self,
|
||||
arms: Box<[ArmId]>,
|
||||
built_match_tree: BuiltMatchTree<'tcx>,
|
||||
state_place: Place<'tcx>,
|
||||
span: Span,
|
||||
f: F,
|
||||
) -> BlockAnd<()>
|
||||
where
|
||||
F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<()>,
|
||||
{
|
||||
let region_scope = self.scopes.topmost();
|
||||
let scope = ConstContinuableScope {
|
||||
region_scope,
|
||||
state_place,
|
||||
const_continue_drops: DropTree::new(),
|
||||
arms,
|
||||
built_match_tree,
|
||||
};
|
||||
self.scopes.const_continuable_scopes.push(scope);
|
||||
let normal_exit_block = f(self);
|
||||
let const_continue_scope = self.scopes.const_continuable_scopes.pop().unwrap();
|
||||
assert!(const_continue_scope.region_scope == region_scope);
|
||||
|
||||
let break_block = self.build_exit_tree(
|
||||
const_continue_scope.const_continue_drops,
|
||||
region_scope,
|
||||
span,
|
||||
None,
|
||||
);
|
||||
|
||||
match (normal_exit_block, break_block) {
|
||||
(block, None) => block,
|
||||
(normal_block, Some(exit_block)) => {
|
||||
let target = self.cfg.start_new_block();
|
||||
let source_info = self.source_info(span);
|
||||
self.cfg.terminate(
|
||||
normal_block.into_block(),
|
||||
source_info,
|
||||
TerminatorKind::Goto { target },
|
||||
);
|
||||
self.cfg.terminate(
|
||||
exit_block.into_block(),
|
||||
source_info,
|
||||
TerminatorKind::Goto { target },
|
||||
);
|
||||
target.unit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Start an if-then scope which tracks drop for `if` expressions and `if`
|
||||
/// guards.
|
||||
///
|
||||
|
|
@ -742,6 +816,190 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.cfg.start_new_block().unit()
|
||||
}
|
||||
|
||||
/// Based on `FunctionCx::eval_unevaluated_mir_constant_to_valtree`.
|
||||
fn eval_unevaluated_mir_constant_to_valtree(
|
||||
&self,
|
||||
constant: ConstOperand<'tcx>,
|
||||
) -> Result<(ty::ValTree<'tcx>, Ty<'tcx>), interpret::ErrorHandled> {
|
||||
assert!(!constant.const_.ty().has_param());
|
||||
let (uv, ty) = match constant.const_ {
|
||||
mir::Const::Unevaluated(uv, ty) => (uv.shrink(), ty),
|
||||
mir::Const::Ty(_, c) => match c.kind() {
|
||||
// A constant that came from a const generic but was then used as an argument to
|
||||
// old-style simd_shuffle (passing as argument instead of as a generic param).
|
||||
ty::ConstKind::Value(cv) => return Ok((cv.valtree, cv.ty)),
|
||||
other => span_bug!(constant.span, "{other:#?}"),
|
||||
},
|
||||
mir::Const::Val(mir::ConstValue::Scalar(mir::interpret::Scalar::Int(val)), ty) => {
|
||||
return Ok((ValTree::from_scalar_int(self.tcx, val), ty));
|
||||
}
|
||||
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
|
||||
// a constant and write that value back into `Operand`s. This could happen, but is
|
||||
// unlikely. Also: all users of `simd_shuffle` are on unstable and already need to take
|
||||
// a lot of care around intrinsics. For an issue to happen here, it would require a
|
||||
// macro expanding to a `simd_shuffle` call without wrapping the constant argument in a
|
||||
// `const {}` block, but the user pass through arbitrary expressions.
|
||||
|
||||
// FIXME(oli-obk): Replace the magic const generic argument of `simd_shuffle` with a
|
||||
// real const generic, and get rid of this entire function.
|
||||
other => span_bug!(constant.span, "{other:#?}"),
|
||||
};
|
||||
|
||||
match self.tcx.const_eval_resolve_for_typeck(self.typing_env(), uv, constant.span) {
|
||||
Ok(Ok(valtree)) => Ok((valtree, ty)),
|
||||
Ok(Err(ty)) => span_bug!(constant.span, "could not convert {ty:?} to a valtree"),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the drops for jumping from `block` to `scope`.
|
||||
pub(crate) fn break_const_continuable_scope(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
value: ExprId,
|
||||
scope: region::Scope,
|
||||
source_info: SourceInfo,
|
||||
) -> BlockAnd<()> {
|
||||
let span = source_info.span;
|
||||
|
||||
// A break can only break out of a scope, so the value should be a scope.
|
||||
let rustc_middle::thir::ExprKind::Scope { value, .. } = self.thir[value].kind else {
|
||||
span_bug!(span, "break value must be a scope")
|
||||
};
|
||||
|
||||
let constant = match &self.thir[value].kind {
|
||||
ExprKind::Adt(box AdtExpr { variant_index, fields, base, .. }) => {
|
||||
assert!(matches!(base, AdtExprBase::None));
|
||||
assert!(fields.is_empty());
|
||||
ConstOperand {
|
||||
span: self.thir[value].span,
|
||||
user_ty: None,
|
||||
const_: Const::Ty(
|
||||
self.thir[value].ty,
|
||||
ty::Const::new_value(
|
||||
self.tcx,
|
||||
ValTree::from_branches(
|
||||
self.tcx,
|
||||
[ValTree::from_scalar_int(self.tcx, variant_index.as_u32().into())],
|
||||
),
|
||||
self.thir[value].ty,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => self.as_constant(&self.thir[value]),
|
||||
};
|
||||
|
||||
let break_index = self
|
||||
.scopes
|
||||
.const_continuable_scopes
|
||||
.iter()
|
||||
.rposition(|const_continuable_scope| const_continuable_scope.region_scope == scope)
|
||||
.unwrap_or_else(|| span_bug!(span, "no enclosing const-continuable scope found"));
|
||||
|
||||
let scope = &self.scopes.const_continuable_scopes[break_index];
|
||||
|
||||
let state_decl = &self.local_decls[scope.state_place.as_local().unwrap()];
|
||||
let state_ty = state_decl.ty;
|
||||
let (discriminant_ty, rvalue) = match state_ty.kind() {
|
||||
ty::Adt(adt_def, _) if adt_def.is_enum() => {
|
||||
(state_ty.discriminant_ty(self.tcx), Rvalue::Discriminant(scope.state_place))
|
||||
}
|
||||
ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Bool | ty::Char => {
|
||||
(state_ty, Rvalue::Use(Operand::Copy(scope.state_place)))
|
||||
}
|
||||
_ => span_bug!(state_decl.source_info.span, "unsupported #[loop_match] state"),
|
||||
};
|
||||
|
||||
// The `PatCtxt` is normally used in pattern exhaustiveness checking, but reused
|
||||
// here because it performs normalization and const evaluation.
|
||||
let dropless_arena = rustc_arena::DroplessArena::default();
|
||||
let typeck_results = self.tcx.typeck(self.def_id);
|
||||
let cx = RustcPatCtxt {
|
||||
tcx: self.tcx,
|
||||
typeck_results,
|
||||
module: self.tcx.parent_module(self.hir_id).to_def_id(),
|
||||
// FIXME(#132279): We're in a body, should handle opaques.
|
||||
typing_env: rustc_middle::ty::TypingEnv::non_body_analysis(self.tcx, self.def_id),
|
||||
dropless_arena: &dropless_arena,
|
||||
match_lint_level: self.hir_id,
|
||||
whole_match_span: Some(rustc_span::Span::default()),
|
||||
scrut_span: rustc_span::Span::default(),
|
||||
refutable: true,
|
||||
known_valid_scrutinee: true,
|
||||
};
|
||||
|
||||
let valtree = match self.eval_unevaluated_mir_constant_to_valtree(constant) {
|
||||
Ok((valtree, ty)) => {
|
||||
// Defensively check that the type is monomorphic.
|
||||
assert!(!ty.has_param());
|
||||
|
||||
valtree
|
||||
}
|
||||
Err(ErrorHandled::Reported(..)) => return self.cfg.start_new_block().unit(),
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
self.tcx.dcx().emit_fatal(ConstContinueBadConst { span: constant.span });
|
||||
}
|
||||
};
|
||||
|
||||
let Some(real_target) =
|
||||
self.static_pattern_match(&cx, valtree, &*scope.arms, &scope.built_match_tree)
|
||||
else {
|
||||
self.tcx.dcx().emit_fatal(ConstContinueUnknownJumpTarget { span })
|
||||
};
|
||||
|
||||
self.block_context.push(BlockFrame::SubExpr);
|
||||
let state_place = scope.state_place;
|
||||
block = self.expr_into_dest(state_place, block, value).into_block();
|
||||
self.block_context.pop();
|
||||
|
||||
let discr = self.temp(discriminant_ty, source_info.span);
|
||||
let scope_index = self
|
||||
.scopes
|
||||
.scope_index(self.scopes.const_continuable_scopes[break_index].region_scope, span);
|
||||
let scope = &mut self.scopes.const_continuable_scopes[break_index];
|
||||
self.cfg.push_assign(block, source_info, discr, rvalue);
|
||||
let drop_and_continue_block = self.cfg.start_new_block();
|
||||
let imaginary_target = self.cfg.start_new_block();
|
||||
self.cfg.terminate(
|
||||
block,
|
||||
source_info,
|
||||
TerminatorKind::FalseEdge { real_target: drop_and_continue_block, imaginary_target },
|
||||
);
|
||||
|
||||
let drops = &mut scope.const_continue_drops;
|
||||
|
||||
let drop_idx = self.scopes.scopes[scope_index + 1..]
|
||||
.iter()
|
||||
.flat_map(|scope| &scope.drops)
|
||||
.fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx));
|
||||
|
||||
drops.add_entry_point(imaginary_target, drop_idx);
|
||||
|
||||
self.cfg.terminate(imaginary_target, source_info, TerminatorKind::UnwindResume);
|
||||
|
||||
let region_scope = scope.region_scope;
|
||||
let scope_index = self.scopes.scope_index(region_scope, span);
|
||||
let mut drops = DropTree::new();
|
||||
|
||||
let drop_idx = self.scopes.scopes[scope_index + 1..]
|
||||
.iter()
|
||||
.flat_map(|scope| &scope.drops)
|
||||
.fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx));
|
||||
|
||||
drops.add_entry_point(drop_and_continue_block, drop_idx);
|
||||
|
||||
// `build_drop_trees` doesn't have access to our source_info, so we
|
||||
// create a dummy terminator now. `TerminatorKind::UnwindResume` is used
|
||||
// because MIR type checking will panic if it hasn't been overwritten.
|
||||
// (See `<ExitScopes as DropTreeBuilder>::link_entry_point`.)
|
||||
self.cfg.terminate(drop_and_continue_block, source_info, TerminatorKind::UnwindResume);
|
||||
|
||||
self.build_exit_tree(drops, region_scope, span, Some(real_target));
|
||||
|
||||
return self.cfg.start_new_block().unit();
|
||||
}
|
||||
|
||||
/// Sets up the drops for breaking from `block` due to an `if` condition
|
||||
/// that turned out to be false.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -465,10 +465,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
| ExprKind::Break { .. }
|
||||
| ExprKind::Closure { .. }
|
||||
| ExprKind::Continue { .. }
|
||||
| ExprKind::ConstContinue { .. }
|
||||
| ExprKind::Return { .. }
|
||||
| ExprKind::Become { .. }
|
||||
| ExprKind::Yield { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::LoopMatch { .. }
|
||||
| ExprKind::Let { .. }
|
||||
| ExprKind::Match { .. }
|
||||
| ExprKind::Box { .. }
|
||||
|
|
|
|||
|
|
@ -1149,3 +1149,80 @@ impl Subdiagnostic for Rust2024IncompatiblePatSugg {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_loop_match_invalid_update)]
|
||||
pub(crate) struct LoopMatchInvalidUpdate {
|
||||
#[primary_span]
|
||||
pub lhs: Span,
|
||||
#[label]
|
||||
pub scrutinee: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_loop_match_invalid_match)]
|
||||
#[note]
|
||||
pub(crate) struct LoopMatchInvalidMatch {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_loop_match_unsupported_type)]
|
||||
#[note]
|
||||
pub(crate) struct LoopMatchUnsupportedType<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_loop_match_bad_statements)]
|
||||
pub(crate) struct LoopMatchBadStatements {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_loop_match_bad_rhs)]
|
||||
pub(crate) struct LoopMatchBadRhs {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_loop_match_missing_assignment)]
|
||||
pub(crate) struct LoopMatchMissingAssignment {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_loop_match_arm_with_guard)]
|
||||
pub(crate) struct LoopMatchArmWithGuard {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_const_continue_bad_const)]
|
||||
pub(crate) struct ConstContinueBadConst {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_const_continue_missing_value)]
|
||||
pub(crate) struct ConstContinueMissingValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_const_continue_unknown_jump_target)]
|
||||
#[note]
|
||||
pub(crate) struct ConstContinueUnknownJumpTarget {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use itertools::Itertools;
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||
use rustc_ast::UnsafeBinderCastKind;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
|
|
@ -21,6 +22,7 @@ use rustc_middle::{bug, span_bug};
|
|||
use rustc_span::{Span, sym};
|
||||
use tracing::{debug, info, instrument, trace};
|
||||
|
||||
use crate::errors::*;
|
||||
use crate::thir::cx::ThirBuildCx;
|
||||
|
||||
impl<'tcx> ThirBuildCx<'tcx> {
|
||||
|
|
@ -479,6 +481,55 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
|
||||
}
|
||||
|
||||
// Make `&pin mut $expr` and `&pin const $expr` into
|
||||
// `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`.
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() {
|
||||
&ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => {
|
||||
let ty = args.type_at(0);
|
||||
let arg_ty = self.typeck_results.expr_ty(arg_expr);
|
||||
let mut arg = self.mirror_expr(arg_expr);
|
||||
// For `&pin mut $place` where `$place` is not `Unpin`, move the place
|
||||
// `$place` to ensure it will not be used afterwards.
|
||||
if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) {
|
||||
let block = self.thir.blocks.push(Block {
|
||||
targeted_by_break: false,
|
||||
region_scope: region::Scope {
|
||||
local_id: arg_expr.hir_id.local_id,
|
||||
data: region::ScopeData::Node,
|
||||
},
|
||||
span: arg_expr.span,
|
||||
stmts: Box::new([]),
|
||||
expr: Some(arg),
|
||||
safety_mode: BlockSafety::Safe,
|
||||
});
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id);
|
||||
arg = self.thir.exprs.push(Expr {
|
||||
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
|
||||
ty: arg_ty,
|
||||
span: arg_expr.span,
|
||||
kind: ExprKind::Block { block },
|
||||
});
|
||||
}
|
||||
let expr = self.thir.exprs.push(Expr {
|
||||
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
|
||||
ty,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
|
||||
});
|
||||
ExprKind::Adt(Box::new(AdtExpr {
|
||||
adt_def,
|
||||
variant_index: FIRST_VARIANT,
|
||||
args,
|
||||
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
|
||||
user_ty: None,
|
||||
base: AdtExprBase::None,
|
||||
}))
|
||||
}
|
||||
_ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty),
|
||||
},
|
||||
|
||||
hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
|
||||
|
||||
hir::ExprKind::Assign(lhs, rhs, _) => {
|
||||
|
|
@ -796,16 +847,38 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
}
|
||||
hir::ExprKind::Ret(v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
|
||||
hir::ExprKind::Become(call) => ExprKind::Become { value: self.mirror_expr(call) },
|
||||
hir::ExprKind::Break(dest, ref value) => match dest.target_id {
|
||||
Ok(target_id) => ExprKind::Break {
|
||||
label: region::Scope {
|
||||
local_id: target_id.local_id,
|
||||
data: region::ScopeData::Node,
|
||||
},
|
||||
value: value.map(|value| self.mirror_expr(value)),
|
||||
},
|
||||
Err(err) => bug!("invalid loop id for break: {}", err),
|
||||
},
|
||||
hir::ExprKind::Break(dest, ref value) => {
|
||||
if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::ConstContinue(_)) {
|
||||
match dest.target_id {
|
||||
Ok(target_id) => {
|
||||
let Some(value) = value else {
|
||||
let span = expr.span;
|
||||
self.tcx.dcx().emit_fatal(ConstContinueMissingValue { span })
|
||||
};
|
||||
|
||||
ExprKind::ConstContinue {
|
||||
label: region::Scope {
|
||||
local_id: target_id.local_id,
|
||||
data: region::ScopeData::Node,
|
||||
},
|
||||
value: self.mirror_expr(value),
|
||||
}
|
||||
}
|
||||
Err(err) => bug!("invalid loop id for break: {}", err),
|
||||
}
|
||||
} else {
|
||||
match dest.target_id {
|
||||
Ok(target_id) => ExprKind::Break {
|
||||
label: region::Scope {
|
||||
local_id: target_id.local_id,
|
||||
data: region::ScopeData::Node,
|
||||
},
|
||||
value: value.map(|value| self.mirror_expr(value)),
|
||||
},
|
||||
Err(err) => bug!("invalid loop id for break: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Continue(dest) => match dest.target_id {
|
||||
Ok(loop_id) => ExprKind::Continue {
|
||||
label: region::Scope {
|
||||
|
|
@ -840,18 +913,93 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
match_source,
|
||||
},
|
||||
hir::ExprKind::Loop(body, ..) => {
|
||||
let block_ty = self.typeck_results.node_type(body.hir_id);
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, body.hir_id.local_id);
|
||||
let block = self.mirror_block(body);
|
||||
let body = self.thir.exprs.push(Expr {
|
||||
ty: block_ty,
|
||||
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
|
||||
span: self.thir[block].span,
|
||||
kind: ExprKind::Block { block },
|
||||
});
|
||||
ExprKind::Loop { body }
|
||||
if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::LoopMatch(_)) {
|
||||
let dcx = self.tcx.dcx();
|
||||
|
||||
// Accept either `state = expr` or `state = expr;`.
|
||||
let loop_body_expr = match body.stmts {
|
||||
[] => match body.expr {
|
||||
Some(expr) => expr,
|
||||
None => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }),
|
||||
},
|
||||
[single] if body.expr.is_none() => match single.kind {
|
||||
hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => expr,
|
||||
_ => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }),
|
||||
},
|
||||
[first @ last] | [first, .., last] => dcx
|
||||
.emit_fatal(LoopMatchBadStatements { span: first.span.to(last.span) }),
|
||||
};
|
||||
|
||||
let hir::ExprKind::Assign(state, rhs_expr, _) = loop_body_expr.kind else {
|
||||
dcx.emit_fatal(LoopMatchMissingAssignment { span: loop_body_expr.span })
|
||||
};
|
||||
|
||||
let hir::ExprKind::Block(block_body, _) = rhs_expr.kind else {
|
||||
dcx.emit_fatal(LoopMatchBadRhs { span: rhs_expr.span })
|
||||
};
|
||||
|
||||
// The labeled block should contain one match expression, but defining items is
|
||||
// allowed.
|
||||
for stmt in block_body.stmts {
|
||||
if !matches!(stmt.kind, rustc_hir::StmtKind::Item(_)) {
|
||||
dcx.emit_fatal(LoopMatchBadStatements { span: stmt.span })
|
||||
}
|
||||
}
|
||||
|
||||
let Some(block_body_expr) = block_body.expr else {
|
||||
dcx.emit_fatal(LoopMatchBadRhs { span: block_body.span })
|
||||
};
|
||||
|
||||
let hir::ExprKind::Match(scrutinee, arms, _match_source) = block_body_expr.kind
|
||||
else {
|
||||
dcx.emit_fatal(LoopMatchBadRhs { span: block_body_expr.span })
|
||||
};
|
||||
|
||||
fn local(expr: &rustc_hir::Expr<'_>) -> Option<hir::HirId> {
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
|
||||
if let Res::Local(hir_id) = path.res {
|
||||
return Some(hir_id);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
let Some(scrutinee_hir_id) = local(scrutinee) else {
|
||||
dcx.emit_fatal(LoopMatchInvalidMatch { span: scrutinee.span })
|
||||
};
|
||||
|
||||
if local(state) != Some(scrutinee_hir_id) {
|
||||
dcx.emit_fatal(LoopMatchInvalidUpdate {
|
||||
scrutinee: scrutinee.span,
|
||||
lhs: state.span,
|
||||
})
|
||||
}
|
||||
|
||||
ExprKind::LoopMatch {
|
||||
state: self.mirror_expr(state),
|
||||
region_scope: region::Scope {
|
||||
local_id: block_body.hir_id.local_id,
|
||||
data: region::ScopeData::Node,
|
||||
},
|
||||
|
||||
arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
|
||||
match_span: block_body_expr.span,
|
||||
}
|
||||
} else {
|
||||
let block_ty = self.typeck_results.node_type(body.hir_id);
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, body.hir_id.local_id);
|
||||
let block = self.mirror_block(body);
|
||||
let body = self.thir.exprs.push(Expr {
|
||||
ty: block_ty,
|
||||
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
|
||||
span: self.thir[block].span,
|
||||
kind: ExprKind::Block { block },
|
||||
});
|
||||
ExprKind::Loop { body }
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Field(source, ..) => ExprKind::Field {
|
||||
lhs: self.mirror_expr(source),
|
||||
|
|
|
|||
|
|
@ -331,7 +331,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||
| WrapUnsafeBinder { source } => self.is_known_valid_scrutinee(&self.thir()[*source]),
|
||||
|
||||
// These diverge.
|
||||
Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true,
|
||||
Become { .. }
|
||||
| Break { .. }
|
||||
| Continue { .. }
|
||||
| ConstContinue { .. }
|
||||
| Return { .. } => true,
|
||||
|
||||
// These are statements that evaluate to `()`.
|
||||
Assign { .. } | AssignOp { .. } | InlineAsm { .. } | Let { .. } => true,
|
||||
|
|
@ -353,6 +357,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||
| Literal { .. }
|
||||
| LogicalOp { .. }
|
||||
| Loop { .. }
|
||||
| LoopMatch { .. }
|
||||
| Match { .. }
|
||||
| NamedConst { .. }
|
||||
| NonHirLiteral { .. }
|
||||
|
|
|
|||
|
|
@ -318,6 +318,20 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
self.print_expr(*body, depth_lvl + 2);
|
||||
print_indented!(self, ")", depth_lvl);
|
||||
}
|
||||
LoopMatch { state, region_scope, match_span, arms } => {
|
||||
print_indented!(self, "LoopMatch {", depth_lvl);
|
||||
print_indented!(self, "state:", depth_lvl + 1);
|
||||
self.print_expr(*state, depth_lvl + 2);
|
||||
print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
|
||||
print_indented!(self, format!("match_span: {:?}", match_span), depth_lvl + 1);
|
||||
|
||||
print_indented!(self, "arms: [", depth_lvl + 1);
|
||||
for arm_id in arms.iter() {
|
||||
self.print_arm(*arm_id, depth_lvl + 2);
|
||||
}
|
||||
print_indented!(self, "]", depth_lvl + 1);
|
||||
print_indented!(self, "}", depth_lvl);
|
||||
}
|
||||
Let { expr, pat } => {
|
||||
print_indented!(self, "Let {", depth_lvl);
|
||||
print_indented!(self, "expr:", depth_lvl + 1);
|
||||
|
|
@ -415,6 +429,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
|
||||
print_indented!(self, "}", depth_lvl);
|
||||
}
|
||||
ConstContinue { label, value } => {
|
||||
print_indented!(self, "ConstContinue (", depth_lvl);
|
||||
print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
|
||||
print_indented!(self, "value:", depth_lvl + 1);
|
||||
self.print_expr(*value, depth_lvl + 2);
|
||||
print_indented!(self, ")", depth_lvl);
|
||||
}
|
||||
Return { value } => {
|
||||
print_indented!(self, "Return {", depth_lvl);
|
||||
print_indented!(self, "value:", depth_lvl + 1);
|
||||
|
|
|
|||
|
|
@ -847,7 +847,7 @@ impl<'a> Parser<'a> {
|
|||
self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
|
||||
}
|
||||
|
||||
/// Parse `mut?` or `raw [ const | mut ]`.
|
||||
/// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
|
||||
fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
|
||||
if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
|
||||
// `raw [ const | mut ]`.
|
||||
|
|
@ -855,6 +855,11 @@ impl<'a> Parser<'a> {
|
|||
assert!(found_raw);
|
||||
let mutability = self.parse_const_or_mut().unwrap();
|
||||
(ast::BorrowKind::Raw, mutability)
|
||||
} else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
|
||||
// `pin [ const | mut ]`.
|
||||
// `pin` has been gated in `self.parse_pin_and_mut()` so we don't
|
||||
// need to gate it here.
|
||||
(ast::BorrowKind::Pin, mutbl)
|
||||
} else {
|
||||
// `mut?`
|
||||
(ast::BorrowKind::Ref, self.parse_mutability())
|
||||
|
|
|
|||
|
|
@ -301,6 +301,7 @@ fn emit_malformed_attribute(
|
|||
| sym::naked
|
||||
| sym::no_mangle
|
||||
| sym::must_use
|
||||
| sym::track_caller
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,11 +82,14 @@ passes_collapse_debuginfo =
|
|||
passes_confusables = attribute should be applied to an inherent method
|
||||
.label = not an inherent method
|
||||
|
||||
passes_const_continue_attr =
|
||||
`#[const_continue]` should be applied to a break expression
|
||||
.label = not a break expression
|
||||
|
||||
passes_const_stable_not_stable =
|
||||
attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
|
||||
.label = attribute specified here
|
||||
|
||||
|
||||
passes_coroutine_on_non_closure =
|
||||
attribute should be applied to closures
|
||||
.label = not a closure
|
||||
|
|
@ -446,6 +449,10 @@ passes_linkage =
|
|||
attribute should be applied to a function or static
|
||||
.label = not a function definition or static
|
||||
|
||||
passes_loop_match_attr =
|
||||
`#[loop_match]` should be applied to a loop
|
||||
.label = not a loop
|
||||
|
||||
passes_macro_export =
|
||||
`#[macro_export]` only has an effect on macro definitions
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => {
|
||||
self.check_optimize(hir_id, *attr_span, span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::LoopMatch(attr_span)) => {
|
||||
self.check_loop_match(hir_id, *attr_span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => {
|
||||
self.check_const_continue(hir_id, *attr_span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self
|
||||
.check_allow_internal_unstable(
|
||||
hir_id,
|
||||
|
|
@ -169,6 +175,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
|
||||
self.check_naked(hir_id, *attr_span, span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => {
|
||||
self.check_track_caller(hir_id, *attr_span, attrs, span, target)
|
||||
}
|
||||
Attribute::Parsed(
|
||||
AttributeKind::BodyStability { .. }
|
||||
| AttributeKind::ConstStabilityIndirect
|
||||
|
|
@ -205,9 +214,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.check_target_feature(hir_id, attr, span, target, attrs)
|
||||
}
|
||||
[sym::thread_local, ..] => self.check_thread_local(attr, span, target),
|
||||
[sym::track_caller, ..] => {
|
||||
self.check_track_caller(hir_id, attr.span(), attrs, span, target)
|
||||
}
|
||||
[sym::doc, ..] => self.check_doc_attrs(
|
||||
attr,
|
||||
attr_item.style,
|
||||
|
|
@ -722,9 +728,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
// erroneously allowed it and some crates used it accidentally, to be compatible
|
||||
// with crates depending on them, we can't throw an error here.
|
||||
Target::Field | Target::Arm | Target::MacroDef => {
|
||||
for attr in attrs {
|
||||
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller");
|
||||
}
|
||||
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "track_caller");
|
||||
}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::TrackedCallerWrongLocation {
|
||||
|
|
@ -2633,6 +2637,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_loop_match(&self, hir_id: HirId, attr_span: Span, target: Target) {
|
||||
let node_span = self.tcx.hir_span(hir_id);
|
||||
|
||||
if !matches!(target, Target::Expression) {
|
||||
self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span });
|
||||
return;
|
||||
}
|
||||
|
||||
if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Loop(..)) {
|
||||
self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span });
|
||||
};
|
||||
}
|
||||
|
||||
fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) {
|
||||
let node_span = self.tcx.hir_span(hir_id);
|
||||
|
||||
if !matches!(target, Target::Expression) {
|
||||
self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
|
||||
return;
|
||||
}
|
||||
|
||||
if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Break(..)) {
|
||||
self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,24 @@ pub(crate) struct AutoDiffAttr {
|
|||
pub attr_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_loop_match_attr)]
|
||||
pub(crate) struct LoopMatchAttr {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub node_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_const_continue_attr)]
|
||||
pub(crate) struct ConstContinueAttr {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub node_span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_outer_crate_level_attr)]
|
||||
pub(crate) struct OuterCrateLevelAttr;
|
||||
|
|
|
|||
|
|
@ -314,7 +314,8 @@ impl IntRange {
|
|||
IntRange { lo, hi }
|
||||
}
|
||||
|
||||
fn is_subrange(&self, other: &Self) -> bool {
|
||||
#[inline]
|
||||
pub fn is_subrange(&self, other: &Self) -> bool {
|
||||
other.lo <= self.lo && self.hi <= other.hi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -494,6 +494,7 @@ impl RustcInternal for Abi {
|
|||
Abi::RustCall => rustc_abi::ExternAbi::RustCall,
|
||||
Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted,
|
||||
Abi::RustCold => rustc_abi::ExternAbi::RustCold,
|
||||
Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid,
|
||||
Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM,
|
||||
Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS,
|
||||
Abi::Custom => rustc_abi::ExternAbi::Custom,
|
||||
|
|
|
|||
|
|
@ -877,6 +877,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
|
|||
ExternAbi::RustCall => Abi::RustCall,
|
||||
ExternAbi::Unadjusted => Abi::Unadjusted,
|
||||
ExternAbi::RustCold => Abi::RustCold,
|
||||
ExternAbi::RustInvalid => Abi::RustInvalid,
|
||||
ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM,
|
||||
ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS,
|
||||
ExternAbi::Custom => Abi::Custom,
|
||||
|
|
|
|||
|
|
@ -1126,6 +1126,7 @@ pub enum Abi {
|
|||
RustCold,
|
||||
RiscvInterruptM,
|
||||
RiscvInterruptS,
|
||||
RustInvalid,
|
||||
Custom,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -693,6 +693,7 @@ symbols! {
|
|||
const_closures,
|
||||
const_compare_raw_pointers,
|
||||
const_constructor,
|
||||
const_continue,
|
||||
const_deallocate,
|
||||
const_destruct,
|
||||
const_eval_limit,
|
||||
|
|
@ -1305,6 +1306,7 @@ symbols! {
|
|||
logf64,
|
||||
loongarch_target_feature,
|
||||
loop_break_value,
|
||||
loop_match,
|
||||
lt,
|
||||
m68k_target_feature,
|
||||
macro_at_most_once_rep,
|
||||
|
|
|
|||
|
|
@ -156,7 +156,8 @@ impl AbiMap {
|
|||
| ExternAbi::Msp430Interrupt
|
||||
| ExternAbi::RiscvInterruptM
|
||||
| ExternAbi::RiscvInterruptS
|
||||
| ExternAbi::X86Interrupt,
|
||||
| ExternAbi::X86Interrupt
|
||||
| ExternAbi::RustInvalid,
|
||||
_,
|
||||
) => return AbiMapping::Invalid,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -226,7 +226,11 @@ fn recurse_build<'tcx>(
|
|||
ExprKind::Yield { .. } => {
|
||||
error(GenericConstantTooComplexSub::YieldNotSupported(node.span))?
|
||||
}
|
||||
ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => {
|
||||
ExprKind::Continue { .. }
|
||||
| ExprKind::ConstContinue { .. }
|
||||
| ExprKind::Break { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::LoopMatch { .. } => {
|
||||
error(GenericConstantTooComplexSub::LoopNotSupported(node.span))?
|
||||
}
|
||||
ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?,
|
||||
|
|
@ -329,6 +333,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
|
|||
| thir::ExprKind::NeverToAny { .. }
|
||||
| thir::ExprKind::PointerCoercion { .. }
|
||||
| thir::ExprKind::Loop { .. }
|
||||
| thir::ExprKind::LoopMatch { .. }
|
||||
| thir::ExprKind::Let { .. }
|
||||
| thir::ExprKind::Match { .. }
|
||||
| thir::ExprKind::Block { .. }
|
||||
|
|
@ -342,6 +347,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
|
|||
| thir::ExprKind::RawBorrow { .. }
|
||||
| thir::ExprKind::Break { .. }
|
||||
| thir::ExprKind::Continue { .. }
|
||||
| thir::ExprKind::ConstContinue { .. }
|
||||
| thir::ExprKind::Return { .. }
|
||||
| thir::ExprKind::Become { .. }
|
||||
| thir::ExprKind::Array { .. }
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ impl CStr {
|
|||
/// // 💀 this violates `CStr::from_ptr`'s safety contract
|
||||
/// // 💀 leading to a dereference of a dangling pointer,
|
||||
/// // 💀 which is immediate undefined behavior.
|
||||
/// // 💀 *BOOM*, you're dead, you're entire program has no meaning.
|
||||
/// // 💀 *BOOM*, you're dead, your entire program has no meaning.
|
||||
/// dbg!(unsafe { CStr::from_ptr(ptr) });
|
||||
/// ```
|
||||
///
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ impl Iterator for ReadDir {
|
|||
let mut wfd = mem::zeroed();
|
||||
loop {
|
||||
if c::FindNextFileW(handle.0, &mut wfd) == 0 {
|
||||
self.handle = None;
|
||||
match api::get_last_error() {
|
||||
WinError::NO_MORE_FILES => return None,
|
||||
WinError { code } => {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ generated code is normally invisible to the programmer.
|
|||
|
||||
This flag helps identify such cases. When enabled, the compiler measures the
|
||||
effect on code size of all used macros and prints a table summarizing that
|
||||
effect. For each distinct macro, it counts how many times it is used, and the
|
||||
net effect on code size (in terms of lines of code, and bytes of code). The
|
||||
effect. For each distinct macro, it counts how many times it is used, and how
|
||||
much code it produces when expanded (in lines of code, and bytes of code). The
|
||||
code size evaluation uses the compiler's internal pretty-printing, and so will
|
||||
be independent of the formatting in the original code.
|
||||
|
||||
Note that the net effect of a macro may be negative. E.g. the `cfg!` and
|
||||
Note that the output size of a macro may be zero. E.g. the `cfg!` and
|
||||
`#[test]` macros often strip out code.
|
||||
|
||||
If a macro is identified as causing a large increase in code size, it is worth
|
||||
|
|
|
|||
52
src/doc/unstable-book/src/language-features/loop-match.md
Normal file
52
src/doc/unstable-book/src/language-features/loop-match.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# `loop_match`
|
||||
|
||||
The tracking issue for this feature is: [#132306]
|
||||
|
||||
[#132306]: https://github.com/rust-lang/rust/issues/132306
|
||||
|
||||
------
|
||||
|
||||
The `#[loop_match]` and `#[const_continue]` attributes can be used to improve the code
|
||||
generation of logic that fits this shape:
|
||||
|
||||
```ignore (pseudo-rust)
|
||||
loop {
|
||||
state = 'blk: {
|
||||
match state {
|
||||
State::A => {
|
||||
break 'blk State::B
|
||||
}
|
||||
State::B => { /* ... */ }
|
||||
/* ... */
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here the loop itself can be annotated with `#[loop_match]`, and any `break 'blk` with
|
||||
`#[const_continue]` if the value is know at compile time:
|
||||
|
||||
```ignore (pseudo-rust)
|
||||
#[loop_match]
|
||||
loop {
|
||||
state = 'blk: {
|
||||
match state {
|
||||
State::A => {
|
||||
#[const_continue]
|
||||
break 'blk State::B
|
||||
}
|
||||
State::B => { /* ... */ }
|
||||
/* ... */
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The observable behavior of this loop is exactly the same as without the extra attributes.
|
||||
The difference is in the generated output: normally, when the state is `A`, control flow
|
||||
moves from the `A` branch, back to the top of the loop, then to the `B` branch. With the
|
||||
attributes, The `A` branch will immediately jump to the `B` branch.
|
||||
|
||||
Removing the indirection can be beneficial for stack usage and branch prediction, and
|
||||
enables other optimizations by clearly splitting out the control flow paths that your
|
||||
program will actually use.
|
||||
|
|
@ -469,7 +469,8 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
|
|||
|
||||
let unsafety_flag = match myitem.kind {
|
||||
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
|
||||
if myitem.fn_header(tcx).unwrap().is_unsafe() =>
|
||||
if myitem.fn_header(tcx).unwrap().safety
|
||||
== hir::HeaderSafety::Normal(hir::Safety::Unsafe) =>
|
||||
{
|
||||
"<sup title=\"unsafe function\">⚠</sup>"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 84709f085062cbf3c51fa507527c1b2334015178
|
||||
Subproject commit 409fed7dc1553d49cb9a8c0637d12d65571346ce
|
||||
|
|
@ -7,6 +7,7 @@ use clippy_utils::{
|
|||
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
|
||||
};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
|
|
@ -155,7 +156,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
let sig = match callee_ty_adjusted.kind() {
|
||||
ty::FnDef(def, _) => {
|
||||
// Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
|
||||
if cx.tcx.has_attr(*def, sym::track_caller) {
|
||||
if find_attr!(cx.tcx.get_all_attrs(*def), AttributeKind::TrackCaller(..)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +237,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
},
|
||||
ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
|
||||
if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
|
||||
&& !cx.tcx.has_attr(method_def_id, sym::track_caller)
|
||||
&& !find_attr!(cx.tcx.get_all_attrs(method_def_id), AttributeKind::TrackCaller(..))
|
||||
&& check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
|
||||
{
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
|
|
|
|||
|
|
@ -2289,8 +2289,10 @@ fn rewrite_expr_addrof(
|
|||
) -> RewriteResult {
|
||||
let operator_str = match (mutability, borrow_kind) {
|
||||
(ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
|
||||
(ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ",
|
||||
(ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
|
||||
(ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
|
||||
(ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ",
|
||||
(ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
|
||||
};
|
||||
rewrite_unary_prefix(context, operator_str, expr, shape)
|
||||
|
|
|
|||
|
|
@ -18,3 +18,13 @@ impl Foo {
|
|||
mut self) {}
|
||||
fn i(&pin mut self) {}
|
||||
}
|
||||
|
||||
fn borrows() {
|
||||
let mut foo = 0_i32;
|
||||
let x: Pin<&mut _> = & pin
|
||||
mut foo;
|
||||
|
||||
let x: Pin<&_> = &
|
||||
pin const
|
||||
foo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,3 +16,10 @@ impl Foo {
|
|||
fn h<'a>(&'a pin mut self) {}
|
||||
fn i(&pin mut self) {}
|
||||
}
|
||||
|
||||
fn borrows() {
|
||||
let mut foo = 0_i32;
|
||||
let x: Pin<&mut _> = &pin mut foo;
|
||||
|
||||
let x: Pin<&_> = &pin const foo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"scoped-tls",
|
||||
"scopeguard",
|
||||
"self_cell",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@ name = "wasm-component-ld"
|
|||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
wasm-component-ld = "0.5.13"
|
||||
wasm-component-ld = "0.5.14"
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
|
||||
// CHECK: define x86_intrcc void @has_x86_interrupt_abi
|
||||
#[no_mangle]
|
||||
pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 {
|
||||
a
|
||||
}
|
||||
pub extern "x86-interrupt" fn has_x86_interrupt_abi() {}
|
||||
|
|
|
|||
|
|
@ -55,3 +55,48 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
|
|||
pub fn int_to_ptr(i: usize) -> *mut u16 {
|
||||
unsafe { std::mem::transmute(i) }
|
||||
}
|
||||
|
||||
// This is the one case where signedness matters to transmuting:
|
||||
// the LLVM type is `i8` here because of `repr(i8)`,
|
||||
// whereas below with the `repr(u8)` it's `i1` in LLVM instead.
|
||||
#[repr(i8)]
|
||||
pub enum FakeBoolSigned {
|
||||
False = 0,
|
||||
True = 1,
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1 zeroext %b)
|
||||
// CHECK: %_0 = zext i1 %b to i8
|
||||
// CHECK-NEXT: ret i8 %_0
|
||||
#[no_mangle]
|
||||
pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b)
|
||||
// CHECK: %_0 = trunc nuw i8 %b to i1
|
||||
// CHECK-NEXT: ret i1 %_0
|
||||
#[no_mangle]
|
||||
pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum FakeBoolUnsigned {
|
||||
False = 0,
|
||||
True = 1,
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1 zeroext %b)
|
||||
// CHECK: ret i1 %b
|
||||
#[no_mangle]
|
||||
pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b)
|
||||
// CHECK: ret i1 %b
|
||||
#[no_mangle]
|
||||
pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
}
|
||||
|
|
|
|||
44
tests/pretty/pin-ergonomics-hir.pp
Normal file
44
tests/pretty/pin-ergonomics-hir.pp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
//@ pretty-compare-only
|
||||
//@ pretty-mode:hir
|
||||
//@ pp-exact:pin-ergonomics-hir.pp
|
||||
|
||||
#![feature(pin_ergonomics)]
|
||||
#![allow(dead_code, incomplete_features)]
|
||||
#[prelude_import]
|
||||
use ::std::prelude::rust_2015::*;
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn baz(&mut self) { }
|
||||
|
||||
fn baz_const(&self) { }
|
||||
|
||||
fn baz_lt<'a>(&mut self) { }
|
||||
|
||||
fn baz_const_lt(&self) { }
|
||||
}
|
||||
|
||||
fn foo(_: Pin<&'_ mut Foo>) { }
|
||||
fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
|
||||
|
||||
fn foo_const(_: Pin<&'_ Foo>) { }
|
||||
fn foo_const_lt(_: Pin<&'_ Foo>) { }
|
||||
|
||||
fn bar() {
|
||||
let mut x: Pin<&mut _> = &pin mut Foo;
|
||||
foo(x.as_mut());
|
||||
foo(x.as_mut());
|
||||
foo_const(x);
|
||||
|
||||
let x: Pin<&_> = &pin const Foo;
|
||||
|
||||
foo_const(x);
|
||||
foo_const(x);
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
40
tests/pretty/pin-ergonomics-hir.rs
Normal file
40
tests/pretty/pin-ergonomics-hir.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//@ pretty-compare-only
|
||||
//@ pretty-mode:hir
|
||||
//@ pp-exact:pin-ergonomics-hir.pp
|
||||
|
||||
#![feature(pin_ergonomics)]
|
||||
#![allow(dead_code, incomplete_features)]
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn baz(&mut self) { }
|
||||
|
||||
fn baz_const(&self) { }
|
||||
|
||||
fn baz_lt<'a>(&mut self) { }
|
||||
|
||||
fn baz_const_lt(&self) { }
|
||||
}
|
||||
|
||||
fn foo(_: Pin<&'_ mut Foo>) { }
|
||||
fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
|
||||
|
||||
fn foo_const(_: Pin<&'_ Foo>) { }
|
||||
fn foo_const_lt(_: Pin<&'_ Foo>) { }
|
||||
|
||||
fn bar() {
|
||||
let mut x: Pin<&mut _> = &pin mut Foo;
|
||||
foo(x.as_mut());
|
||||
foo(x.as_mut());
|
||||
foo_const(x);
|
||||
|
||||
let x: Pin<&_> = &pin const Foo;
|
||||
|
||||
foo_const(x);
|
||||
foo_const(x);
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
#![feature(pin_ergonomics)]
|
||||
#![allow(dead_code, incomplete_features)]
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
|
|
@ -21,4 +23,15 @@ fn foo_lt<'a>(_: &'a pin mut Foo) {}
|
|||
fn foo_const(_: &pin const Foo) {}
|
||||
fn foo_const_lt(_: &'_ pin const Foo) {}
|
||||
|
||||
fn bar() {
|
||||
let mut x: Pin<&mut _> = &pin mut Foo;
|
||||
foo(x.as_mut());
|
||||
foo(x.as_mut());
|
||||
foo_const(x);
|
||||
|
||||
let x: Pin<&_> = &pin const Foo;
|
||||
foo_const(x);
|
||||
foo_const(x);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,15 @@ fn panic(_: &PanicInfo) -> ! {
|
|||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh() {}
|
||||
fn eh(
|
||||
_version: i32,
|
||||
_actions: i32,
|
||||
_exception_class: u64,
|
||||
_exception_object: *mut (),
|
||||
_context: *mut (),
|
||||
) -> i32 {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn oom(_: Layout) -> ! {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@ extern "C" fn __rust_foreign_exception() -> ! {
|
|||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() {
|
||||
fn eh_personality(
|
||||
_version: i32,
|
||||
_actions: i32,
|
||||
_exception_class: u64,
|
||||
_exception_object: *mut (),
|
||||
_context: *mut (),
|
||||
) -> i32 {
|
||||
loop {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ fn main() {
|
|||
diff()
|
||||
.expected_file("short-error.txt")
|
||||
.actual_text("(linker error)", out.stderr())
|
||||
.normalize(r#"/rustc[^/]*/"#, "/rustc/")
|
||||
.normalize(r#"/rustc[^/_-]*/"#, "/rustc/")
|
||||
.normalize("libpanic_abort", "libpanic_unwind")
|
||||
.normalize(
|
||||
regex::escape(run_make_support::build_root().to_str().unwrap()),
|
||||
"/build-root",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,13 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn rust_eh_personality() {
|
||||
extern "C" fn rust_eh_personality(
|
||||
_version: i32,
|
||||
_actions: i32,
|
||||
_exception_class: u64,
|
||||
_exception_object: *mut (),
|
||||
_context: *mut (),
|
||||
) -> i32 {
|
||||
loop {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
// See https://github.com/rust-lang/rust/issues/107910
|
||||
|
||||
//@ needs-target-std
|
||||
//@ ignore-windows
|
||||
// Reason: the assert_eq! on line 32 fails, as error output on Windows is different.
|
||||
//@ ignore-i686-pc-windows-msvc
|
||||
// Reason: the assert_eq! on line 37 fails, almost seems like it missing debug info?
|
||||
// Haven't been able to reproduce locally, but it happens on CI.
|
||||
|
||||
use run_make_support::rustc;
|
||||
|
||||
|
|
@ -29,10 +30,16 @@ fn main() {
|
|||
|
||||
let rustc_query_count_full = count_lines_with(rust_test_log_2, "rustc_query_");
|
||||
|
||||
assert!(rust_test_log_1.lines().count() < rust_test_log_2.lines().count());
|
||||
assert!(
|
||||
rust_test_log_1.lines().count() < rust_test_log_2.lines().count(),
|
||||
"Short backtrace should be shorter than full backtrace.\nShort backtrace:\n\
|
||||
{rust_test_log_1}\nFull backtrace:\n{rust_test_log_2}"
|
||||
);
|
||||
assert_eq!(
|
||||
count_lines_with(rust_test_log_2, "__rust_begin_short_backtrace"),
|
||||
count_lines_with(rust_test_log_2, "__rust_end_short_backtrace")
|
||||
count_lines_with(rust_test_log_2, "__rust_end_short_backtrace"),
|
||||
"Full backtrace should contain the short backtrace markers.\nFull backtrace:\n\
|
||||
{rust_test_log_2}"
|
||||
);
|
||||
assert!(count_lines_with(rust_test_log_1, "rustc_query_") + 5 < rustc_query_count_full);
|
||||
assert!(rustc_query_count_full > 5);
|
||||
|
|
|
|||
38
tests/rustdoc/target-feature.rs
Normal file
38
tests/rustdoc/target-feature.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#![crate_name = "foo"]
|
||||
|
||||
//@ has 'foo/index.html'
|
||||
|
||||
//@ has - '//dl[@class="item-table"]/dt[1]//a' 'f1_safe'
|
||||
//@ has - '//dl[@class="item-table"]/dt[1]//code' 'popcnt'
|
||||
//@ count - '//dl[@class="item-table"]/dt[1]//sup' 0
|
||||
//@ has - '//dl[@class="item-table"]/dt[2]//a' 'f2_not_safe'
|
||||
//@ has - '//dl[@class="item-table"]/dt[2]//code' 'avx2'
|
||||
//@ count - '//dl[@class="item-table"]/dt[2]//sup' 1
|
||||
//@ has - '//dl[@class="item-table"]/dt[2]//sup' '⚠'
|
||||
|
||||
#[target_feature(enable = "popcnt")]
|
||||
//@ has 'foo/fn.f1_safe.html'
|
||||
//@ matches - '//pre[@class="rust item-decl"]' '^pub fn f1_safe'
|
||||
//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
|
||||
// 'Available with target feature popcnt only.'
|
||||
pub fn f1_safe() {}
|
||||
|
||||
//@ has 'foo/fn.f2_not_safe.html'
|
||||
//@ matches - '//pre[@class="rust item-decl"]' '^pub unsafe fn f2_not_safe()'
|
||||
//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
|
||||
// 'Available with target feature avx2 only.'
|
||||
#[target_feature(enable = "avx2")]
|
||||
pub unsafe fn f2_not_safe() {}
|
||||
|
||||
//@ has 'foo/fn.f3_multifeatures_in_attr.html'
|
||||
//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
|
||||
// 'Available on target features popcnt and avx2 only.'
|
||||
#[target_feature(enable = "popcnt", enable = "avx2")]
|
||||
pub fn f3_multifeatures_in_attr() {}
|
||||
|
||||
//@ has 'foo/fn.f4_multi_attrs.html'
|
||||
//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
|
||||
// 'Available on target features popcnt and avx2 only.'
|
||||
#[target_feature(enable = "popcnt")]
|
||||
#[target_feature(enable = "avx2")]
|
||||
pub fn f4_multi_attrs() {}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#[unsafe(naked)]
|
||||
extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
//~^ ERROR functions with the `"custom"` ABI must be unsafe
|
||||
//~^ ERROR functions with the "custom" ABI must be unsafe
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
std::arch::naked_asm!("")
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ unsafe extern "custom" fn no_return_type() -> i64 {
|
|||
}
|
||||
|
||||
unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ struct Thing(i64);
|
|||
|
||||
impl Thing {
|
||||
unsafe extern "custom" fn is_even(self) -> bool {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ impl Thing {
|
|||
|
||||
trait BitwiseNot {
|
||||
unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -50,14 +50,14 @@ impl BitwiseNot for Thing {}
|
|||
|
||||
trait Negate {
|
||||
extern "custom" fn negate(a: i64) -> i64;
|
||||
//~^ ERROR functions with the `"custom"` ABI must be unsafe
|
||||
//~^ ERROR functions with the "custom" ABI must be unsafe
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
}
|
||||
|
||||
impl Negate for Thing {
|
||||
extern "custom" fn negate(a: i64) -> i64 {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR functions with the `"custom"` ABI must be unsafe
|
||||
//~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR functions with the "custom" ABI must be unsafe
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
-a
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ unsafe extern "custom" {
|
|||
//~^ ERROR invalid signature for `extern "custom"` function
|
||||
|
||||
safe fn extern_cannot_be_safe();
|
||||
//~^ ERROR foreign functions with the `"custom"` ABI cannot be safe
|
||||
//~^ ERROR foreign functions with the "custom" ABI cannot be safe
|
||||
}
|
||||
|
||||
fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
|
||||
|
|
@ -95,8 +95,8 @@ const unsafe extern "custom" fn no_const_fn() {
|
|||
}
|
||||
|
||||
async unsafe extern "custom" fn no_async_fn() {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR functions with the `"custom"` ABI cannot be `async`
|
||||
//~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR functions with the "custom" ABI cannot be `async`
|
||||
}
|
||||
|
||||
fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error: functions with the `"custom"` ABI must be unsafe
|
||||
error: functions with the "custom" ABI must be unsafe
|
||||
--> $DIR/bad-custom.rs:7:1
|
||||
|
|
||||
LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
|
|
@ -15,7 +15,7 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
|
|
@ -28,7 +28,7 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | unsafe extern "custom" fn no_parameters(a: i64) {
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn no_parameters(a: i64) {
|
||||
|
|
@ -41,7 +41,7 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | unsafe extern "custom" fn no_return_type() -> i64 {
|
||||
| ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn no_return_type() -> i64 {
|
||||
|
|
@ -54,7 +54,7 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
|
|
@ -67,7 +67,7 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | unsafe extern "custom" fn is_even(self) -> bool {
|
||||
| ^^^^ ^^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn is_even(self) -> bool {
|
||||
|
|
@ -80,14 +80,14 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
LL + unsafe extern "custom" fn bitwise_not() {
|
||||
|
|
||||
|
||||
error: functions with the `"custom"` ABI must be unsafe
|
||||
error: functions with the "custom" ABI must be unsafe
|
||||
--> $DIR/bad-custom.rs:52:5
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64;
|
||||
|
|
@ -104,14 +104,14 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | extern "custom" fn negate(a: i64) -> i64;
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - extern "custom" fn negate(a: i64) -> i64;
|
||||
LL + extern "custom" fn negate();
|
||||
|
|
||||
|
||||
error: functions with the `"custom"` ABI must be unsafe
|
||||
error: functions with the "custom" ABI must be unsafe
|
||||
--> $DIR/bad-custom.rs:58:5
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
|
|
@ -128,7 +128,7 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - extern "custom" fn negate(a: i64) -> i64 {
|
||||
|
|
@ -141,14 +141,14 @@ error: invalid signature for `extern "custom"` function
|
|||
LL | fn increment(a: i64) -> i64;
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
= note: functions with the "custom" ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - fn increment(a: i64) -> i64;
|
||||
LL + fn increment();
|
||||
|
|
||||
|
||||
error: foreign functions with the `"custom"` ABI cannot be safe
|
||||
error: foreign functions with the "custom" ABI cannot be safe
|
||||
--> $DIR/bad-custom.rs:70:5
|
||||
|
|
||||
LL | safe fn extern_cannot_be_safe();
|
||||
|
|
@ -160,7 +160,7 @@ LL - safe fn extern_cannot_be_safe();
|
|||
LL + fn extern_cannot_be_safe();
|
||||
|
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be `async`
|
||||
error: functions with the "custom" ABI cannot be `async`
|
||||
--> $DIR/bad-custom.rs:97:1
|
||||
|
|
||||
LL | async unsafe extern "custom" fn no_async_fn() {
|
||||
|
|
@ -172,7 +172,7 @@ LL - async unsafe extern "custom" fn no_async_fn() {
|
|||
LL + unsafe extern "custom" fn no_async_fn() {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
error: items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:97:1
|
||||
|
|
||||
LL | async unsafe extern "custom" fn no_async_fn() {
|
||||
|
|
@ -197,7 +197,7 @@ LL | f
|
|||
= note: unsafe function cannot be called generically without an unsafe block
|
||||
= note: wrap the `unsafe extern "custom" fn()` in a closure with no arguments: `|| { /* code */ }`
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
error: items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:25:1
|
||||
|
|
||||
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
|
|
@ -209,7 +209,7 @@ LL + #[unsafe(naked)]
|
|||
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
error: items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:34:5
|
||||
|
|
||||
LL | unsafe extern "custom" fn is_even(self) -> bool {
|
||||
|
|
@ -221,7 +221,7 @@ LL + #[unsafe(naked)]
|
|||
LL | unsafe extern "custom" fn is_even(self) -> bool {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
error: items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:42:5
|
||||
|
|
||||
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
|
|
@ -233,7 +233,7 @@ LL + #[unsafe(naked)]
|
|||
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
error: items with the "custom" ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:58:5
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:38:8
|
||||
--> $DIR/cannot-be-called.rs:37:8
|
||||
|
|
||||
LL | extern "msp430-interrupt" fn msp430() {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:42:8
|
||||
--> $DIR/cannot-be-called.rs:41:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-m" fn riscv_m() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:44:8
|
||||
--> $DIR/cannot-be-called.rs:43:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-s" fn riscv_s() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:46:8
|
||||
--> $DIR/cannot-be-called.rs:45:8
|
||||
|
|
||||
LL | extern "x86-interrupt" fn x86() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:65:25
|
||||
--> $DIR/cannot-be-called.rs:70:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:77:26
|
||||
--> $DIR/cannot-be-called.rs:76:26
|
||||
|
|
||||
LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:83:26
|
||||
--> $DIR/cannot-be-called.rs:82:26
|
||||
|
|
||||
LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:89:22
|
||||
--> $DIR/cannot-be-called.rs:88:22
|
||||
|
|
||||
LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the "avr-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:53:5
|
||||
--> $DIR/cannot-be-called.rs:50:5
|
||||
|
|
||||
LL | avr();
|
||||
| ^^^^^
|
||||
|
|
||||
note: an `extern "avr-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:53:5
|
||||
--> $DIR/cannot-be-called.rs:50:5
|
||||
|
|
||||
LL | avr();
|
||||
| ^^^^^
|
||||
|
||||
error: functions with the "avr-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:73:5
|
||||
--> $DIR/cannot-be-called.rs:66:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "avr-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:73:5
|
||||
--> $DIR/cannot-be-called.rs:66:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:38:8
|
||||
--> $DIR/cannot-be-called.rs:37:8
|
||||
|
|
||||
LL | extern "msp430-interrupt" fn msp430() {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:40:8
|
||||
--> $DIR/cannot-be-called.rs:39:8
|
||||
|
|
||||
LL | extern "avr-interrupt" fn avr() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:42:8
|
||||
--> $DIR/cannot-be-called.rs:41:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-m" fn riscv_m() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:44:8
|
||||
--> $DIR/cannot-be-called.rs:43:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-s" fn riscv_s() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:65:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:71:22
|
||||
--> $DIR/cannot-be-called.rs:64:22
|
||||
|
|
||||
LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:70:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:77:26
|
||||
--> $DIR/cannot-be-called.rs:76:26
|
||||
|
|
||||
LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:83:26
|
||||
--> $DIR/cannot-be-called.rs:82:26
|
||||
|
|
||||
LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the "x86-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:59:5
|
||||
--> $DIR/cannot-be-called.rs:58:5
|
||||
|
|
||||
LL | x86();
|
||||
| ^^^^^
|
||||
|
|
||||
note: an `extern "x86-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:59:5
|
||||
--> $DIR/cannot-be-called.rs:58:5
|
||||
|
|
||||
LL | x86();
|
||||
| ^^^^^
|
||||
|
||||
error: functions with the "x86-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:91:5
|
||||
--> $DIR/cannot-be-called.rs:90:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "x86-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:91:5
|
||||
--> $DIR/cannot-be-called.rs:90:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:40:8
|
||||
--> $DIR/cannot-be-called.rs:39:8
|
||||
|
|
||||
LL | extern "avr-interrupt" fn avr() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:42:8
|
||||
--> $DIR/cannot-be-called.rs:41:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-m" fn riscv_m() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:44:8
|
||||
--> $DIR/cannot-be-called.rs:43:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-s" fn riscv_s() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:46:8
|
||||
--> $DIR/cannot-be-called.rs:45:8
|
||||
|
|
||||
LL | extern "x86-interrupt" fn x86() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:71:22
|
||||
--> $DIR/cannot-be-called.rs:64:22
|
||||
|
|
||||
LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:77:26
|
||||
--> $DIR/cannot-be-called.rs:76:26
|
||||
|
|
||||
LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:83:26
|
||||
--> $DIR/cannot-be-called.rs:82:26
|
||||
|
|
||||
LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:89:22
|
||||
--> $DIR/cannot-be-called.rs:88:22
|
||||
|
|
||||
LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the "msp430-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:51:5
|
||||
--> $DIR/cannot-be-called.rs:52:5
|
||||
|
|
||||
LL | msp430();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: an `extern "msp430-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:51:5
|
||||
--> $DIR/cannot-be-called.rs:52:5
|
||||
|
|
||||
LL | msp430();
|
||||
| ^^^^^^^^
|
||||
|
||||
error: functions with the "msp430-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:67:5
|
||||
--> $DIR/cannot-be-called.rs:72:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "msp430-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:67:5
|
||||
--> $DIR/cannot-be-called.rs:72:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
|
|||
|
|
@ -1,83 +1,83 @@
|
|||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:38:8
|
||||
--> $DIR/cannot-be-called.rs:37:8
|
||||
|
|
||||
LL | extern "msp430-interrupt" fn msp430() {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:40:8
|
||||
--> $DIR/cannot-be-called.rs:39:8
|
||||
|
|
||||
LL | extern "avr-interrupt" fn avr() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:46:8
|
||||
--> $DIR/cannot-be-called.rs:45:8
|
||||
|
|
||||
LL | extern "x86-interrupt" fn x86() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:65:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:71:22
|
||||
--> $DIR/cannot-be-called.rs:64:22
|
||||
|
|
||||
LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:70:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:89:22
|
||||
--> $DIR/cannot-be-called.rs:88:22
|
||||
|
|
||||
LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-m" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:55:5
|
||||
--> $DIR/cannot-be-called.rs:54:5
|
||||
|
|
||||
LL | riscv_m();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:55:5
|
||||
--> $DIR/cannot-be-called.rs:54:5
|
||||
|
|
||||
LL | riscv_m();
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-s" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:57:5
|
||||
--> $DIR/cannot-be-called.rs:56:5
|
||||
|
|
||||
LL | riscv_s();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:57:5
|
||||
--> $DIR/cannot-be-called.rs:56:5
|
||||
|
|
||||
LL | riscv_s();
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-m" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:79:5
|
||||
--> $DIR/cannot-be-called.rs:78:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:79:5
|
||||
--> $DIR/cannot-be-called.rs:78:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-s" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:85:5
|
||||
--> $DIR/cannot-be-called.rs:84:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:85:5
|
||||
--> $DIR/cannot-be-called.rs:84:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
|
|||
|
|
@ -1,83 +1,83 @@
|
|||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:38:8
|
||||
--> $DIR/cannot-be-called.rs:37:8
|
||||
|
|
||||
LL | extern "msp430-interrupt" fn msp430() {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:40:8
|
||||
--> $DIR/cannot-be-called.rs:39:8
|
||||
|
|
||||
LL | extern "avr-interrupt" fn avr() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:46:8
|
||||
--> $DIR/cannot-be-called.rs:45:8
|
||||
|
|
||||
LL | extern "x86-interrupt" fn x86() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:65:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:71:22
|
||||
--> $DIR/cannot-be-called.rs:64:22
|
||||
|
|
||||
LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:70:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "x86-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:89:22
|
||||
--> $DIR/cannot-be-called.rs:88:22
|
||||
|
|
||||
LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-m" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:55:5
|
||||
--> $DIR/cannot-be-called.rs:54:5
|
||||
|
|
||||
LL | riscv_m();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:55:5
|
||||
--> $DIR/cannot-be-called.rs:54:5
|
||||
|
|
||||
LL | riscv_m();
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-s" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:57:5
|
||||
--> $DIR/cannot-be-called.rs:56:5
|
||||
|
|
||||
LL | riscv_s();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:57:5
|
||||
--> $DIR/cannot-be-called.rs:56:5
|
||||
|
|
||||
LL | riscv_s();
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-m" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:79:5
|
||||
--> $DIR/cannot-be-called.rs:78:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:79:5
|
||||
--> $DIR/cannot-be-called.rs:78:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
||||
error: functions with the "riscv-interrupt-s" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:85:5
|
||||
--> $DIR/cannot-be-called.rs:84:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:85:5
|
||||
--> $DIR/cannot-be-called.rs:84:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@ So we test that they error in essentially all of the same places.
|
|||
no_core,
|
||||
abi_msp430_interrupt,
|
||||
abi_avr_interrupt,
|
||||
abi_gpu_kernel,
|
||||
abi_x86_interrupt,
|
||||
abi_riscv_interrupt,
|
||||
abi_riscv_interrupt
|
||||
)]
|
||||
|
||||
extern crate minicore;
|
||||
|
|
@ -48,10 +47,10 @@ extern "x86-interrupt" fn x86() {}
|
|||
|
||||
/* extern "interrupt" calls */
|
||||
fn call_the_interrupts() {
|
||||
msp430();
|
||||
//[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called
|
||||
avr();
|
||||
//[avr]~^ ERROR functions with the "avr-interrupt" ABI cannot be called
|
||||
msp430();
|
||||
//[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called
|
||||
riscv_m();
|
||||
//[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called
|
||||
riscv_s();
|
||||
|
|
@ -62,18 +61,18 @@ fn call_the_interrupts() {
|
|||
|
||||
/* extern "interrupt" fnptr calls */
|
||||
|
||||
fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
//[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI
|
||||
f()
|
||||
//[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called
|
||||
}
|
||||
|
||||
fn avr_ptr(f: extern "avr-interrupt" fn()) {
|
||||
//[x64,x64_win,i686,riscv32,riscv64,msp430]~^ ERROR is not a supported ABI
|
||||
f()
|
||||
//[avr]~^ ERROR functions with the "avr-interrupt" ABI cannot be called
|
||||
}
|
||||
|
||||
fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
//[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI
|
||||
f()
|
||||
//[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called
|
||||
}
|
||||
|
||||
fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
|
||||
//[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI
|
||||
f()
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:38:8
|
||||
--> $DIR/cannot-be-called.rs:37:8
|
||||
|
|
||||
LL | extern "msp430-interrupt" fn msp430() {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:40:8
|
||||
--> $DIR/cannot-be-called.rs:39:8
|
||||
|
|
||||
LL | extern "avr-interrupt" fn avr() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:42:8
|
||||
--> $DIR/cannot-be-called.rs:41:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-m" fn riscv_m() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:44:8
|
||||
--> $DIR/cannot-be-called.rs:43:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-s" fn riscv_s() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:65:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:71:22
|
||||
--> $DIR/cannot-be-called.rs:64:22
|
||||
|
|
||||
LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:70:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:77:26
|
||||
--> $DIR/cannot-be-called.rs:76:26
|
||||
|
|
||||
LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:83:26
|
||||
--> $DIR/cannot-be-called.rs:82:26
|
||||
|
|
||||
LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the "x86-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:59:5
|
||||
--> $DIR/cannot-be-called.rs:58:5
|
||||
|
|
||||
LL | x86();
|
||||
| ^^^^^
|
||||
|
|
||||
note: an `extern "x86-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:59:5
|
||||
--> $DIR/cannot-be-called.rs:58:5
|
||||
|
|
||||
LL | x86();
|
||||
| ^^^^^
|
||||
|
||||
error: functions with the "x86-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:91:5
|
||||
--> $DIR/cannot-be-called.rs:90:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "x86-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:91:5
|
||||
--> $DIR/cannot-be-called.rs:90:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:38:8
|
||||
--> $DIR/cannot-be-called.rs:37:8
|
||||
|
|
||||
LL | extern "msp430-interrupt" fn msp430() {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:40:8
|
||||
--> $DIR/cannot-be-called.rs:39:8
|
||||
|
|
||||
LL | extern "avr-interrupt" fn avr() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:42:8
|
||||
--> $DIR/cannot-be-called.rs:41:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-m" fn riscv_m() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:44:8
|
||||
--> $DIR/cannot-be-called.rs:43:8
|
||||
|
|
||||
LL | extern "riscv-interrupt-s" fn riscv_s() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:65:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "avr-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:71:22
|
||||
--> $DIR/cannot-be-called.rs:64:22
|
||||
|
|
||||
LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:70:25
|
||||
|
|
||||
LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:77:26
|
||||
--> $DIR/cannot-be-called.rs:76:26
|
||||
|
|
||||
LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
|
||||
--> $DIR/cannot-be-called.rs:83:26
|
||||
--> $DIR/cannot-be-called.rs:82:26
|
||||
|
|
||||
LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the "x86-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:59:5
|
||||
--> $DIR/cannot-be-called.rs:58:5
|
||||
|
|
||||
LL | x86();
|
||||
| ^^^^^
|
||||
|
|
||||
note: an `extern "x86-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:59:5
|
||||
--> $DIR/cannot-be-called.rs:58:5
|
||||
|
|
||||
LL | x86();
|
||||
| ^^^^^
|
||||
|
||||
error: functions with the "x86-interrupt" ABI cannot be called
|
||||
--> $DIR/cannot-be-called.rs:91:5
|
||||
--> $DIR/cannot-be-called.rs:90:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
||||
note: an `extern "x86-interrupt"` function can only be called using inline assembly
|
||||
--> $DIR/cannot-be-called.rs:91:5
|
||||
--> $DIR/cannot-be-called.rs:90:5
|
||||
|
|
||||
LL | f()
|
||||
| ^^^
|
||||
|
|
|
|||
23
tests/ui/abi/cannot-be-coroutine.avr.stderr
Normal file
23
tests/ui/abi/cannot-be-coroutine.avr.stderr
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
error: functions with the "avr-interrupt" ABI cannot be `async`
|
||||
--> $DIR/cannot-be-coroutine.rs:36:1
|
||||
|
|
||||
LL | async extern "avr-interrupt" fn avr() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the `async` keyword from this definiton
|
||||
|
|
||||
LL - async extern "avr-interrupt" fn avr() {
|
||||
LL + extern "avr-interrupt" fn avr() {
|
||||
|
|
||||
|
||||
error: requires `ResumeTy` lang_item
|
||||
--> $DIR/cannot-be-coroutine.rs:32:19
|
||||
|
|
||||
LL | async fn vanilla(){
|
||||
| ___________________^
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
23
tests/ui/abi/cannot-be-coroutine.i686.stderr
Normal file
23
tests/ui/abi/cannot-be-coroutine.i686.stderr
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
error: functions with the "x86-interrupt" ABI cannot be `async`
|
||||
--> $DIR/cannot-be-coroutine.rs:52:1
|
||||
|
|
||||
LL | async extern "x86-interrupt" fn x86() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the `async` keyword from this definiton
|
||||
|
|
||||
LL - async extern "x86-interrupt" fn x86() {
|
||||
LL + extern "x86-interrupt" fn x86() {
|
||||
|
|
||||
|
||||
error: requires `ResumeTy` lang_item
|
||||
--> $DIR/cannot-be-coroutine.rs:32:19
|
||||
|
|
||||
LL | async fn vanilla(){
|
||||
| ___________________^
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
23
tests/ui/abi/cannot-be-coroutine.msp430.stderr
Normal file
23
tests/ui/abi/cannot-be-coroutine.msp430.stderr
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
error: functions with the "msp430-interrupt" ABI cannot be `async`
|
||||
--> $DIR/cannot-be-coroutine.rs:40:1
|
||||
|
|
||||
LL | async extern "msp430-interrupt" fn msp430() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the `async` keyword from this definiton
|
||||
|
|
||||
LL - async extern "msp430-interrupt" fn msp430() {
|
||||
LL + extern "msp430-interrupt" fn msp430() {
|
||||
|
|
||||
|
||||
error: requires `ResumeTy` lang_item
|
||||
--> $DIR/cannot-be-coroutine.rs:32:19
|
||||
|
|
||||
LL | async fn vanilla(){
|
||||
| ___________________^
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
35
tests/ui/abi/cannot-be-coroutine.riscv32.stderr
Normal file
35
tests/ui/abi/cannot-be-coroutine.riscv32.stderr
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
error: functions with the "riscv-interrupt-m" ABI cannot be `async`
|
||||
--> $DIR/cannot-be-coroutine.rs:44:1
|
||||
|
|
||||
LL | async extern "riscv-interrupt-m" fn riscv_m() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the `async` keyword from this definiton
|
||||
|
|
||||
LL - async extern "riscv-interrupt-m" fn riscv_m() {
|
||||
LL + extern "riscv-interrupt-m" fn riscv_m() {
|
||||
|
|
||||
|
||||
error: functions with the "riscv-interrupt-s" ABI cannot be `async`
|
||||
--> $DIR/cannot-be-coroutine.rs:48:1
|
||||
|
|
||||
LL | async extern "riscv-interrupt-s" fn riscv_s() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the `async` keyword from this definiton
|
||||
|
|
||||
LL - async extern "riscv-interrupt-s" fn riscv_s() {
|
||||
LL + extern "riscv-interrupt-s" fn riscv_s() {
|
||||
|
|
||||
|
||||
error: requires `ResumeTy` lang_item
|
||||
--> $DIR/cannot-be-coroutine.rs:32:19
|
||||
|
|
||||
LL | async fn vanilla(){
|
||||
| ___________________^
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue