Auto merge of #142443 - matthiaskrgr:rollup-l1l6d0v, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#128425 (Make `missing_fragment_specifier` an unconditional error)
 - rust-lang/rust#135927 (retpoline and retpoline-external-thunk flags (target modifiers) to enable retpoline-related target features)
 - rust-lang/rust#140770 (add `extern "custom"` functions)
 - rust-lang/rust#142176 (tests: Split dont-shuffle-bswaps along opt-levels and arches)
 - rust-lang/rust#142248 (Add supported asm types for LoongArch32)
 - rust-lang/rust#142267 (assert more in release in `rustc_ast_lowering`)
 - rust-lang/rust#142274 (Update the stdarch submodule)
 - rust-lang/rust#142276 (Update dependencies in `library/Cargo.lock`)
 - rust-lang/rust#142308 (Upgrade `object`, `addr2line`, and `unwinding` in the standard library)

Failed merges:

 - rust-lang/rust#140920 (Extract some shared code from codegen backend target feature handling)

r? `@ghost`
`@rustbot` modify labels: rollup

try-job: aarch64-apple
try-job: x86_64-msvc-1
try-job: x86_64-gnu
try-job: dist-i586-gnu-i586-i686-musl
try-job: test-various
This commit is contained in:
bors 2025-06-13 17:44:15 +00:00
commit 8da623945f
91 changed files with 1450 additions and 535 deletions

View file

@ -28,6 +28,9 @@ pub enum CanonAbi {
Rust,
RustCold,
/// An ABI that rustc does not know how to call or define.
Custom,
/// ABIs relevant to 32-bit Arm targets
Arm(ArmCall),
/// ABI relevant to GPUs: the entry point for a GPU kernel
@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
CanonAbi::C => ExternAbi::C { unwind: false },
CanonAbi::Rust => ExternAbi::Rust,
CanonAbi::RustCold => ExternAbi::RustCold,
CanonAbi::Custom => ExternAbi::Custom,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,

View file

@ -40,6 +40,11 @@ pub enum ExternAbi {
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
Unadjusted,
/// An ABI that rustc does not know how to call or define. Functions with this ABI can
/// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
/// be called from inline assembly.
Custom,
/// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
/// and only valid on platforms that have a UEFI standard
EfiApi,
@ -141,6 +146,7 @@ abi_impls! {
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
Cdecl { unwind: false } =><= "cdecl",
Cdecl { unwind: true } =><= "cdecl-unwind",
Custom =><= "custom",
EfiApi =><= "efiapi",
Fastcall { unwind: false } =><= "fastcall",
Fastcall { unwind: true } =><= "fastcall-unwind",

View file

@ -3542,6 +3542,38 @@ impl FnHeader {
|| matches!(constness, Const::Yes(_))
|| !matches!(ext, Extern::None)
}
/// Return a span encompassing the header, or none if all options are default.
pub fn span(&self) -> Option<Span> {
fn append(a: &mut Option<Span>, b: Span) {
*a = match a {
None => Some(b),
Some(x) => Some(x.to(b)),
}
}
let mut full_span = None;
match self.safety {
Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
Safety::Default => {}
};
if let Some(coroutine_kind) = self.coroutine_kind {
append(&mut full_span, coroutine_kind.span());
}
if let Const::Yes(span) = self.constness {
append(&mut full_span, span);
}
match self.ext {
Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
Extern::None => {}
}
full_span
}
}
impl Default for FnHeader {

View file

@ -63,7 +63,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
for (def_id, info) in lctx.children {
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
debug_assert!(
assert!(
matches!(owner, hir::MaybeOwner::Phantom),
"duplicate copy of {def_id:?} in lctx.children"
);
@ -78,7 +78,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
match node {
AstOwner::NonOwner => {}
AstOwner::Crate(c) => {
debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
self.with_lctx(CRATE_NODE_ID, |lctx| {
let module = lctx.lower_mod(&c.items, &c.spans);
// FIXME(jdonszelman): is dummy span ever a problem here?
@ -1160,7 +1160,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> hir::BodyId {
let body = hir::Body { params, value: self.arena.alloc(value) };
let id = body.id();
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
id
}
@ -1673,8 +1673,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
itctx: ImplTraitContext,
f: impl FnOnce(&mut Self) -> T,
) -> (&'hir hir::Generics<'hir>, T) {
debug_assert!(self.impl_trait_defs.is_empty());
debug_assert!(self.impl_trait_bounds.is_empty());
assert!(self.impl_trait_defs.is_empty());
assert!(self.impl_trait_bounds.is_empty());
// Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
// Note: we used to clone these bounds directly onto the type parameter (and avoid lowering

View file

@ -523,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
) -> LocalDefId {
let parent = self.current_hir_id_owner.def_id;
debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
assert_ne!(node_id, ast::DUMMY_NODE_ID);
assert!(
self.opt_local_def_id(node_id).is_none(),
"adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}",
@ -607,10 +607,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
let item = f(self);
debug_assert_eq!(owner_id, item.def_id());
assert_eq!(owner_id, item.def_id());
// `f` should have consumed all the elements in these vectors when constructing `item`.
debug_assert!(self.impl_trait_defs.is_empty());
debug_assert!(self.impl_trait_bounds.is_empty());
assert!(self.impl_trait_defs.is_empty());
assert!(self.impl_trait_bounds.is_empty());
let info = self.make_owner_info(item);
self.attrs = current_attrs;
@ -918,7 +918,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} else {
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id);
debug_assert_eq!(id.owner, self.current_hir_id_owner);
assert_eq!(id.owner, self.current_hir_id_owner);
let ret = self.arena.alloc_from_iter(lowered_attrs);
// this is possible if an item contained syntactical attribute,
@ -956,10 +956,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
debug_assert_eq!(id.owner, self.current_hir_id_owner);
debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
assert_eq!(id.owner, self.current_hir_id_owner);
assert_eq!(target_id.owner, self.current_hir_id_owner);
if let Some(&a) = self.attrs.get(&target_id.local_id) {
debug_assert!(!a.is_empty());
assert!(!a.is_empty());
self.attrs.insert(id.local_id, a);
}
}
@ -1438,7 +1438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
self.resolver.get_lifetime_res(t.id)
{
debug_assert_eq!(start.plus(1), end);
assert_eq!(start.plus(1), end);
start
} else {
self.next_node_id()
@ -1846,16 +1846,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let res = match res {
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
LifetimeRes::Fresh { param, .. } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
assert_eq!(ident.name, kw::UnderscoreLifetime);
let param = self.local_def_id(param);
hir::LifetimeKind::Param(param)
}
LifetimeRes::Infer => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
assert_eq!(ident.name, kw::UnderscoreLifetime);
hir::LifetimeKind::Infer
}
LifetimeRes::Static { .. } => {
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
hir::LifetimeKind::Static
}
LifetimeRes::Error => hir::LifetimeKind::Error,
@ -2285,7 +2285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::Stmt<'hir> {
let hir_id = self.next_id();
if let Some(a) = attrs {
debug_assert!(!a.is_empty());
assert!(!a.is_empty());
self.attrs.insert(hir_id.local_id, a);
}
let local = hir::LetStmt {

View file

@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
feature: sym::cmse_nonsecure_entry,
explain: GateReason::Experimental,
}),
ExternAbi::Custom => {
Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
}
}
}

View file

@ -1,3 +1,20 @@
ast_passes_abi_custom_coroutine =
functions with the `"custom"` 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
.suggestion = remove the `safe` keyword from this definition
ast_passes_abi_custom_safe_function =
functions with the `"custom"` ABI must be unsafe
.suggestion = add the `unsafe` keyword to this definition
ast_passes_assoc_const_without_body =
associated constant in `impl` without body
.suggestion = provide a definition for the constant

View file

@ -18,6 +18,7 @@
use std::mem;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use itertools::{Either, Itertools};
use rustc_abi::ExternAbi;
@ -81,6 +82,7 @@ struct AstValidator<'a> {
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
extern_mod_safety: Option<Safety>,
extern_mod_abi: Option<ExternAbi>,
lint_node_id: NodeId,
@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
self.outer_trait_or_trait_impl = old;
}
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
fn with_in_extern_mod(
&mut self,
extern_mod_safety: Safety,
abi: Option<ExternAbi>,
f: impl FnOnce(&mut Self),
) {
let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
f(self);
self.extern_mod_safety = old;
self.extern_mod_safety = old_safety;
self.extern_mod_abi = old_abi;
}
fn with_tilde_const(
@ -370,6 +379,65 @@ 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) {
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));
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 {
span: sig.span,
unsafe_span: sig.span.shrink_to_lo(),
});
}
},
}
// An `extern "custom"` function cannot be `async` and/or `gen`.
if let Some(coroutine_kind) = sig.header.coroutine_kind {
let coroutine_kind_span = self
.sess
.psess
.source_map()
.span_until_non_whitespace(coroutine_kind.span().to(sig.span));
self.dcx().emit_err(errors::AbiCustomCoroutine {
span: sig.span,
coroutine_kind_span,
coroutine_kind_str: coroutine_kind.as_str(),
});
}
// An `extern "custom"` function must not have any parameters or return type.
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);
}
if !spans.is_empty() {
let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
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 {
spans,
symbol: ident.name,
suggestion_span,
padding,
});
}
}
/// This ensures that items can only be `unsafe` (or unmarked) outside of extern
/// blocks.
///
@ -1005,7 +1073,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if abi.is_none() {
self.handle_missing_abi(*extern_span, item.id);
}
self.with_in_extern_mod(*safety, |this| {
let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok());
self.with_in_extern_mod(*safety, extern_abi, |this| {
visit::walk_item(this, item);
});
self.extern_mod_span = old_item;
@ -1145,6 +1215,9 @@ 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);
}
}
ForeignItemKind::TyAlias(box TyAlias {
defaultness,
@ -1352,6 +1425,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_item_safety(span, safety);
}
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())
{
self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
}
self.check_c_variadic_type(fk);
// Functions cannot both be `const async` or `const gen`
@ -1703,6 +1783,7 @@ pub fn check_crate(
outer_impl_trait_span: None,
disallow_tilde_const: Some(TildeConstReason::Item),
extern_mod_safety: None,
extern_mod_abi: None,
lint_node_id: CRATE_NODE_ID,
is_sdylib_interface,
lint_buffer: lints,

View file

@ -824,3 +824,67 @@ pub(crate) struct MissingAbi {
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_safe_foreign_function)]
pub(crate) struct AbiCustomSafeForeignFunction {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "",
style = "verbose"
)]
pub safe_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_safe_function)]
pub(crate) struct AbiCustomSafeFunction {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "unsafe ",
style = "verbose"
)]
pub unsafe_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_coroutine)]
pub(crate) struct AbiCustomCoroutine {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "",
style = "verbose"
)]
pub coroutine_kind_span: Span,
pub coroutine_kind_str: &'static str,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_invalid_signature)]
#[note]
pub(crate) struct AbiCustomInvalidSignature {
#[primary_span]
pub spans: Vec<Span>,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "{padding}fn {symbol}()",
style = "verbose"
)]
pub suggestion_span: Span,
pub symbol: Symbol,
pub padding: &'static str,
}

View file

@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv(
CanonAbi::Rust | CanonAbi::C => default_call_conv,
CanonAbi::RustCold => CallConv::Cold,
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
CanonAbi::Custom => default_call_conv,
CanonAbi::X86(x86_call) => match x86_call {
X86Call::SysV64 => CallConv::SystemV,
X86Call::Win64 => CallConv::WindowsFastcall,

View file

@ -2,9 +2,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it
codegen_gcc_forbidden_ctarget_feature =
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
codegen_gcc_unwinding_inline_asm =
GCC backend does not support unwinding from inline asm
@ -26,10 +23,6 @@ codegen_gcc_unknown_ctarget_feature =
.possible_feature = you might have meant: `{$rust_feature}`
.consider_filing_feature_request = consider filing a feature request
codegen_gcc_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future
codegen_gcc_missing_features =
add the missing features in a `target_feature` attribute

View file

@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
let attribute = match conv {
CanonAbi::C | CanonAbi::Rust => return None,
CanonAbi::RustCold => FnAttribute::Cold,
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
CanonAbi::Custom => return None,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
},
CanonAbi::RustCold => FnAttribute::Cold,
CanonAbi::GpuKernel => {
if arch == "amdgpu" {
FnAttribute::GcnAmdGpuHsaKernel

View file

@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
pub rust_feature: PossibleFeature<'a>,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_forbidden_ctarget_feature)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_gcc_possible_feature)]

View file

@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_session::Session;
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
use smallvec::{SmallVec, smallvec};
use crate::errors::{
ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
UnstableCTargetFeature,
};
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
let mut features: Vec<&str> = Vec::new();
retpoline_features_by_flags(sess, &mut features);
features
}
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(feature))
@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
sess.dcx().emit_warn(unknown_feature);
}
Some(&(_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. (It makes little sense
// to hard-error here since we just warn about fully unknown
// features above).
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
stability.verify_feature_enabled_by_flag(sess, enable, feature);
}
}

View file

@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto =
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
codegen_llvm_forbidden_ctarget_feature =
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
codegen_llvm_from_llvm_diag = {$message}
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
@ -76,10 +71,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
codegen_llvm_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
codegen_llvm_write_ir = failed to write LLVM IR to {$path}

View file

@ -649,6 +649,10 @@ impl llvm::CallConv {
match conv {
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
CanonAbi::RustCold => llvm::PreserveMost,
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
CanonAbi::Custom => llvm::CCallConv,
CanonAbi::GpuKernel => {
if arch == "amdgpu" {
llvm::AmdgpuKernel

View file

@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
pub rust_feature: PossibleFeature<'a>,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_forbidden_ctarget_feature)]
#[note]
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_llvm_possible_feature)]

View file

@ -16,6 +16,7 @@ use rustc_fs_util::path_to_c_string;
use rustc_middle::bug;
use rustc_session::Session;
use rustc_session::config::{PrintKind, PrintRequest};
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
use rustc_span::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
@ -23,8 +24,7 @@ use smallvec::{SmallVec, smallvec};
use crate::back::write::create_informational_target_machine;
use crate::errors::{
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
};
use crate::llvm;
@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
handle_native(cpu_name)
}
fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
let mut features: Vec<&str> = Vec::new();
retpoline_features_by_flags(sess, &mut features);
features
}
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
pub(crate) fn global_llvm_features(
@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features(
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(feature))
@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features(
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. It makes little sense
// to hard-error here since we just warn about fully unknown
// features above.
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
stability.verify_feature_enabled_by_flag(sess, enable, feature);
}
}

View file

@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::features::StabilityExt;
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
@ -66,7 +67,7 @@ pub(crate) fn from_target_feature_attr(
// Only allow target features whose feature gates have been enabled
// and which are permitted to be toggled.
if let Err(reason) = stability.toggle_allowed() {
if let Err(reason) = stability.is_toggle_permitted(tcx.sess) {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature,

View file

@ -113,7 +113,7 @@ expand_meta_var_expr_unrecognized_var =
variable `{$key}` is not recognized in meta-variable expression
expand_missing_fragment_specifier = missing fragment specifier
.note = fragment specifiers must be specified in the 2024 edition
.note = fragment specifiers must be provided
.suggestion_add_fragspec = try adding a specifier here
.valid = {$valid}

View file

@ -112,9 +112,8 @@ use rustc_ast::{DUMMY_NODE_ID, NodeId};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::MultiSpan;
use rustc_lint_defs::BuiltinLintDiag;
use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
use rustc_session::parse::ParseSess;
use rustc_span::edition::Edition;
use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
use smallvec::SmallVec;
@ -266,23 +265,11 @@ fn check_binders(
// Similarly, this can only happen when checking a toplevel macro.
TokenTree::MetaVarDecl(span, name, kind) => {
if kind.is_none() && node_id != DUMMY_NODE_ID {
// FIXME: Report this as a hard error eventually and remove equivalent errors from
// `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once
// as a hard error and then once as a buffered lint.
if span.edition() >= Edition::Edition2024 {
psess.dcx().emit_err(errors::MissingFragmentSpecifier {
span,
add_span: span.shrink_to_hi(),
valid: VALID_FRAGMENT_NAMES_MSG,
});
} else {
psess.buffer_lint(
MISSING_FRAGMENT_SPECIFIER,
span,
node_id,
BuiltinLintDiag::MissingFragmentSpecifier,
);
}
psess.dcx().emit_err(errors::MissingFragmentSpecifier {
span,
add_span: span.shrink_to_hi(),
valid: VALID_FRAGMENT_NAMES_MSG,
});
}
if !macros.is_empty() {
psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");

View file

@ -353,6 +353,8 @@ declare_features! (
(unstable, abi_avr_interrupt, "1.45.0", Some(69664)),
/// Allows `extern "C-cmse-nonsecure-call" fn()`.
(unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)),
/// Allows `extern "custom" fn()`.
(unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)),
/// Allows `extern "gpu-kernel" fn()`.
(unstable, abi_gpu_kernel, "1.86.0", Some(135467)),
/// Allows `extern "msp430-interrupt" fn()`.

View file

@ -1,3 +1,7 @@
hir_analysis_abi_custom_clothed_function =
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}`
.label = ambiguous associated {$assoc_kind} `{$assoc_ident}`

View file

@ -21,7 +21,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::util::Discr;
use rustc_middle::ty::{
AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, fold_regions,
};
use rustc_session::lint::builtin::UNINHABITED_STATIC;
@ -100,6 +100,18 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex
}
}
pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) {
if fn_sig.abi == ExternAbi::Custom {
// Function definitions that use `extern "custom"` must be naked functions.
if !tcx.has_attr(def_id, sym::naked) {
tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction {
span: fn_sig_span,
naked_span: tcx.def_span(def_id).shrink_to_lo(),
});
}
}
}
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);

View file

@ -72,7 +72,7 @@ pub mod wfcheck;
use std::num::NonZero;
pub use check::{check_abi, check_abi_fn_ptr};
pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
use rustc_abi::{ExternAbi, VariantIdx};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};

View file

@ -1698,3 +1698,17 @@ pub(crate) struct SelfInTypeAlias {
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_abi_custom_clothed_function)]
pub(crate) struct AbiCustomClothedFunction {
#[primary_span]
pub span: Span,
#[suggestion(
hir_analysis_suggestion,
applicability = "maybe-incorrect",
code = "#[unsafe(naked)]\n",
style = "short"
)]
pub naked_span: Span,
}

View file

@ -1,3 +1,7 @@
hir_typeck_abi_custom_call =
functions with the `"custom"` ABI cannot be called
.note = an `extern "custom"` function can only be called from within inline assembly
hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
hir_typeck_add_return_type_add = try adding a return type

View file

@ -1,5 +1,6 @@
use std::iter;
use rustc_abi::ExternAbi;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
use rustc_hir::def::{self, CtorKind, Namespace, Res};
@ -83,6 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
while result.is_none() && autoderef.next().is_some() {
result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
}
self.check_call_custom_abi(autoderef.final_ty(false), call_expr.span);
self.register_predicates(autoderef.into_obligations());
let output = match result {
@ -135,6 +137,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
output
}
/// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`.
///
/// These functions have a calling convention that is unknown to rust, hence it cannot generate
/// code for the call. The only way to execute such a function is via inline assembly.
fn check_call_custom_abi(&self, callee_ty: Ty<'tcx>, span: Span) {
let abi = match callee_ty.kind() {
ty::FnDef(def_id, _) => self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi,
ty::FnPtr(_, header) => header.abi,
_ => return,
};
if let ExternAbi::Custom = abi {
self.tcx.dcx().emit_err(errors::AbiCustomCall { span });
}
}
#[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)]
fn try_overloaded_call_step(
&self,

View file

@ -1163,3 +1163,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm {
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_abi_custom_call)]
pub(crate) struct AbiCustomCall {
#[primary_span]
pub span: Span,
}

View file

@ -5,7 +5,7 @@
//!
//! See [`rustc_hir_analysis::check`] for more context on type checking in general.
use rustc_abi::{FIRST_VARIANT, FieldIdx};
use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::unord::UnordMap;
@ -1627,6 +1627,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(method.def_id),
);
// Functions of type `extern "custom" fn(/* ... */)` cannot be called using
// `ExprKind::MethodCall`. These functions have a calling convention that is
// unknown to rust, hence it cannot generate code for the call. The only way
// to execute such a function is via inline assembly.
if let ExternAbi::Custom = method.sig.abi {
self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span });
}
method.sig.output()
}
Err(error) => {

View file

@ -48,7 +48,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_e
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{HirId, HirIdMap, Node};
use rustc_hir_analysis::check::check_abi;
use rustc_hir_analysis::check::{check_abi, check_custom_abi};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
use rustc_middle::query::Providers;
@ -138,7 +138,7 @@ fn typeck_with_inspect<'tcx>(
// for visit the asm expr of the body.
let ty = fcx.check_expr(body.value);
fcx.write_ty(id, ty);
} else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
} else if let Some(hir::FnSig { header, decl, span: fn_sig_span }) = node.fn_sig() {
let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() {
// In the case that we're recovering `fn() -> W<_>` or some other return
// type that has an infer in it, lower the type directly so that it'll
@ -150,6 +150,8 @@ fn typeck_with_inspect<'tcx>(
};
check_abi(tcx, id, span, fn_sig.abi());
check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span);
loops::check(tcx, def_id, body);
// Compute the function signature from point of view of inside the fn.

View file

@ -530,8 +530,6 @@ lint_mismatched_lifetime_syntaxes_suggestion_implicit =
lint_mismatched_lifetime_syntaxes_suggestion_mixed =
one option is to remove the lifetime for references and use the anonymous lifetime for paths
lint_missing_fragment_specifier = missing fragment specifier
lint_missing_unsafe_on_extern = extern blocks should be unsafe
.suggestion = needs `unsafe` before the extern keyword

View file

@ -432,9 +432,6 @@ pub fn decorate_builtin_lint(
BuiltinLintDiag::CfgAttrNoAttributes => {
lints::CfgAttrNoAttributes.decorate_lint(diag);
}
BuiltinLintDiag::MissingFragmentSpecifier => {
lints::MissingFragmentSpecifier.decorate_lint(diag);
}
BuiltinLintDiag::MetaVariableStillRepeating(name) => {
lints::MetaVariableStillRepeating { name }.decorate_lint(diag);
}

View file

@ -618,6 +618,11 @@ fn register_builtins(store: &mut LintStore) {
"converted into hard error, \
see <https://github.com/rust-lang/rust/issues/116558> for more information",
);
store.register_removed(
"missing_fragment_specifier",
"converted into hard error, \
see <https://github.com/rust-lang/rust/issues/40107> for more information",
);
}
fn register_internals(store: &mut LintStore) {

View file

@ -2590,10 +2590,6 @@ pub(crate) struct DuplicateMacroAttribute;
#[diag(lint_cfg_attr_no_attributes)]
pub(crate) struct CfgAttrNoAttributes;
#[derive(LintDiagnostic)]
#[diag(lint_missing_fragment_specifier)]
pub(crate) struct MissingFragmentSpecifier;
#[derive(LintDiagnostic)]
#[diag(lint_metavariable_still_repeating)]
pub(crate) struct MetaVariableStillRepeating {

View file

@ -65,7 +65,6 @@ declare_lint_pass! {
MACRO_USE_EXTERN_CRATE,
META_VARIABLE_MISUSE,
MISSING_ABI,
MISSING_FRAGMENT_SPECIFIER,
MISSING_UNSAFE_ON_EXTERN,
MUST_NOT_SUSPEND,
NAMED_ARGUMENTS_USED_POSITIONALLY,
@ -1417,51 +1416,6 @@ declare_lint! {
};
}
declare_lint! {
/// The `missing_fragment_specifier` lint is issued when an unused pattern in a
/// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not
/// followed by a fragment specifier (e.g. `:expr`).
///
/// This warning can always be fixed by removing the unused pattern in the
/// `macro_rules!` macro definition.
///
/// ### Example
///
/// ```rust,compile_fail,edition2021
/// macro_rules! foo {
/// () => {};
/// ($name) => { };
/// }
///
/// fn main() {
/// foo!();
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// To fix this, remove the unused pattern from the `macro_rules!` macro definition:
///
/// ```rust
/// macro_rules! foo {
/// () => {};
/// }
/// fn main() {
/// foo!();
/// }
/// ```
pub MISSING_FRAGMENT_SPECIFIER,
Deny,
"detects missing fragment specifiers in unused `macro_rules!` patterns",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
report_in_deps: true,
};
}
declare_lint! {
/// The `late_bound_lifetime_arguments` lint detects generic lifetime
/// arguments in path segments with late bound lifetime parameters.

View file

@ -778,7 +778,6 @@ pub enum BuiltinLintDiag {
UnnameableTestItems,
DuplicateMacroAttribute,
CfgAttrNoAttributes,
MissingFragmentSpecifier,
MetaVariableStillRepeating(MacroRulesNormalizedIdent),
MetaVariableWrongOperator,
DuplicateMatcherBinding,

View file

@ -1266,6 +1266,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
| RiscvInterruptS
| CCmseNonSecureCall
| CCmseNonSecureEntry
| Custom
| Unadjusted => false,
Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
}

View file

@ -40,6 +40,11 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it
session_file_write_fail = failed to write `{$path}` due to error `{$err}`
session_forbidden_ctarget_feature =
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64
session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models
@ -132,6 +137,9 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote
session_unleashed_feature_help_named = skipping check for `{$gate}` feature
session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
session_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future
session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
session_unsupported_crate_type_for_target =

View file

@ -2649,6 +2649,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
// -Zretpoline-external-thunk also requires -Zretpoline
if unstable_opts.retpoline_external_thunk {
unstable_opts.retpoline = true;
target_modifiers.insert(
OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline),
"true".to_string(),
);
}
let cg = cg;
let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));

View file

@ -501,3 +501,20 @@ pub(crate) struct SoftFloatIgnored;
#[note]
#[note(session_soft_float_deprecated_issue)]
pub(crate) struct SoftFloatDeprecated;
#[derive(Diagnostic)]
#[diag(session_forbidden_ctarget_feature)]
#[note]
#[note(session_forbidden_ctarget_feature_issue)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
#[derive(Diagnostic)]
#[diag(session_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}

View file

@ -0,0 +1,59 @@
use rustc_target::target_features::Stability;
use crate::Session;
use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature};
pub trait StabilityExt {
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
/// Otherwise, some features also may only be enabled by flag (target modifier).
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
/// `requires_nightly`.)
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>;
/// Check that feature is correctly enabled/disabled by command line flag (emits warnings)
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str);
}
impl StabilityExt for Stability {
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> {
match self {
Stability::Forbidden { reason } => Err(reason),
Stability::TargetModifierOnly { reason, flag } => {
if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) }
}
_ => Ok(()),
}
}
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) {
if let Err(reason) = self.is_toggle_permitted(sess) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if self.requires_nightly().is_some() {
// An unstable feature. Warn about using it. It makes little sense
// to hard-error here since we just warn about fully unknown
// features above.
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
}
}
pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) {
// -Zretpoline without -Zretpoline-external-thunk enables
// retpoline-indirect-branches and retpoline-indirect-calls target features
let unstable_opts = &sess.opts.unstable_opts;
if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
features.push("+retpoline-indirect-branches");
features.push("+retpoline-indirect-calls");
}
// -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
// retpoline-external-thunk, retpoline-indirect-branches and
// retpoline-indirect-calls target features
if unstable_opts.retpoline_external_thunk {
features.push("+retpoline-external-thunk");
features.push("+retpoline-indirect-branches");
features.push("+retpoline-indirect-calls");
}
}

View file

@ -29,6 +29,7 @@ pub use session::*;
pub mod output;
pub use getopts;
pub mod features;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

View file

@ -290,6 +290,14 @@ macro_rules! top_level_options {
mods.sort_by(|a, b| a.opt.cmp(&b.opt));
mods
}
pub fn target_feature_flag_enabled(&self, flag: &str) -> bool {
match flag {
"retpoline" => self.unstable_opts.retpoline,
"retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk,
_ => false,
}
}
}
);
}
@ -2448,6 +2456,11 @@ options! {
remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"directory into which to write optimization remarks (if not specified, they will be \
written to standard error output)"),
retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
"enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"),
retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
"enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
target features (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],

View file

@ -496,6 +496,7 @@ impl RustcInternal for Abi {
Abi::RustCold => rustc_abi::ExternAbi::RustCold,
Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM,
Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS,
Abi::Custom => rustc_abi::ExternAbi::Custom,
}
}
}

View file

@ -101,6 +101,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi {
CanonAbi::C => CallConvention::C,
CanonAbi::Rust => CallConvention::Rust,
CanonAbi::RustCold => CallConvention::Cold,
CanonAbi::Custom => CallConvention::Custom,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::Aapcs => CallConvention::ArmAapcs,
ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,

View file

@ -879,6 +879,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
ExternAbi::RustCold => Abi::RustCold,
ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM,
ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS,
ExternAbi::Custom => Abi::Custom,
}
}
}

View file

@ -430,6 +430,8 @@ pub enum CallConvention {
PreserveMost,
PreserveAll,
Custom,
// Target-specific calling conventions.
ArmAapcs,
CCmseNonSecureCall,

View file

@ -1111,6 +1111,7 @@ pub enum Abi {
RustCold,
RiscvInterruptM,
RiscvInterruptS,
Custom,
}
/// A binder represents a possibly generic type and its bound vars.

View file

@ -407,6 +407,7 @@ symbols! {
abi_amdgpu_kernel,
abi_avr_interrupt,
abi_c_cmse_nonsecure_call,
abi_custom,
abi_efiapi,
abi_gpu_kernel,
abi_msp430_interrupt,

View file

@ -34,11 +34,13 @@ impl LoongArchInlineAsmRegClass {
pub fn supported_types(
self,
_arch: InlineAsmArch,
arch: InlineAsmArch,
) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
Self::freg => types! { f: F32; d: F64; },
match (self, arch) {
(Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; },
(Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F32; },
(Self::freg, _) => types! { f: F32; d: F64; },
_ => unreachable!("unsupported register class"),
}
}
}

View file

@ -71,6 +71,8 @@ impl AbiMap {
(ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
(ExternAbi::RustCold, _) => CanonAbi::RustCold,
(ExternAbi::Custom, _) => CanonAbi::Custom,
(ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => {
CanonAbi::X86(X86Call::Stdcall)
}

View file

@ -34,6 +34,9 @@ pub enum Stability {
/// particular for features are actually ABI configuration flags (not all targets are as nice as
/// RISC-V and have an explicit way to set the ABI separate from target features).
Forbidden { reason: &'static str },
/// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set
/// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules.
TargetModifierOnly { reason: &'static str, flag: &'static str },
}
use Stability::*;
@ -49,6 +52,7 @@ impl<CTX> HashStable<CTX> for Stability {
Stability::Forbidden { reason } => {
reason.hash_stable(hcx, hasher);
}
Stability::TargetModifierOnly { .. } => {}
}
}
}
@ -74,16 +78,7 @@ impl Stability {
Stability::Unstable(nightly_feature) => Some(nightly_feature),
Stability::Stable { .. } => None,
Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
}
}
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
/// `requires_nightly`.)
pub fn toggle_allowed(&self) -> Result<(), &'static str> {
match self {
Stability::Forbidden { reason } => Err(reason),
_ => Ok(()),
Stability::TargetModifierOnly { .. } => None,
}
}
}
@ -453,6 +448,30 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("prfchw", Unstable(sym::prfchw_target_feature), &[]),
("rdrand", Stable, &[]),
("rdseed", Stable, &[]),
(
"retpoline-external-thunk",
Stability::TargetModifierOnly {
reason: "use `retpoline-external-thunk` target modifier flag instead",
flag: "retpoline-external-thunk",
},
&[],
),
(
"retpoline-indirect-branches",
Stability::TargetModifierOnly {
reason: "use `retpoline` target modifier flag instead",
flag: "retpoline",
},
&[],
),
(
"retpoline-indirect-calls",
Stability::TargetModifierOnly {
reason: "use `retpoline` target modifier flag instead",
flag: "retpoline",
},
&[],
),
("rtm", Unstable(sym::rtm_target_feature), &[]),
("sha", Stable, &["sse2"]),
("sha512", Stable, &["avx2"]),

View file

@ -4,11 +4,10 @@ version = 4
[[package]]
name = "addr2line"
version = "0.24.2"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43"
dependencies = [
"compiler_builtins",
"gimli",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
@ -16,11 +15,10 @@ dependencies = [
[[package]]
name = "adler2"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
@ -51,11 +49,10 @@ dependencies = [
[[package]]
name = "cfg-if"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
@ -81,12 +78,11 @@ dependencies = [
[[package]]
name = "dlmalloc"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7"
checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891"
dependencies = [
"cfg-if",
"compiler_builtins",
"libc",
"rustc-std-workspace-core",
"windows-sys",
@ -104,9 +100,9 @@ dependencies = [
[[package]]
name = "getopts"
version = "0.2.21"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
dependencies = [
"rustc-std-workspace-core",
"rustc-std-workspace-std",
@ -115,11 +111,10 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.31.1"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
@ -136,11 +131,10 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
@ -156,33 +150,30 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.4"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
[[package]]
name = "miniz_oxide"
version = "0.8.8"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "object"
version = "0.36.7"
version = "0.37.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a"
dependencies = [
"compiler_builtins",
"memchr",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
@ -273,11 +264,10 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
]
@ -352,7 +342,6 @@ name = "std_detect"
version = "0.1.5"
dependencies = [
"cfg-if",
"compiler_builtins",
"libc",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
@ -380,11 +369,10 @@ dependencies = [
[[package]]
name = "unicode-width"
version = "0.1.14"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
"rustc-std-workspace-std",
]
@ -402,9 +390,9 @@ dependencies = [
[[package]]
name = "unwinding"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345"
checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751"
dependencies = [
"compiler_builtins",
"gimli",
@ -413,11 +401,10 @@ dependencies = [
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]

View file

@ -32,7 +32,7 @@ rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
miniz_oxide = { version = "0.8.0", optional = true, default-features = false }
addr2line = { version = "0.24.0", optional = true, default-features = false }
addr2line = { version = "0.25.0", optional = true, default-features = false }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.172", default-features = false, features = [
@ -40,7 +40,7 @@ libc = { version = "0.2.172", default-features = false, features = [
], public = true }
[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
object = { version = "0.36.0", default-features = false, optional = true, features = [
object = { version = "0.37.1", default-features = false, optional = true, features = [
'read_core',
'elf',
'macho',
@ -50,7 +50,7 @@ object = { version = "0.36.0", default-features = false, optional = true, featur
] }
[target.'cfg(target_os = "aix")'.dependencies]
object = { version = "0.36.0", default-features = false, optional = true, features = [
object = { version = "0.37.1", default-features = false, optional = true, features = [
'read_core',
'xcoff',
'unaligned',

@ -1 +1 @@
Subproject commit 5c1c436524c0bbc8db83577f42f8bea9006a7b75
Subproject commit 1b4d15df12079504942d0a3f1030b2039b8a776c

View file

@ -22,7 +22,7 @@ cfg-if = "1.0"
libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false }
[target.'cfg(target_os = "xous")'.dependencies]
unwinding = { version = "0.2.6", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }
unwinding = { version = "0.2.7", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }
[features]

View file

@ -19,6 +19,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
- M68k
- CSKY
- SPARC
- LoongArch32
## Register classes
@ -53,6 +54,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| CSKY | `freg` | `f[0-31]` | `f` |
| SPARC | `reg` | `r[2-29]` | `r` |
| SPARC | `yreg` | `y` | Only clobbers |
| LoongArch32 | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` |
| LoongArch32 | `freg` | `$f[0-31]` | `f` |
> **Notes**:
> - NVPTX doesn't have a fixed register set, so named registers are not supported.
@ -91,6 +94,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| CSKY | `freg` | None | `f32`, |
| SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) |
| SPARC | `yreg` | N/A | Only clobbers |
| LoongArch32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
| LoongArch32 | `freg` | None | `f32`, `f64` |
## Register aliases

View file

@ -18,6 +18,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::features::StabilityExt;
use rustc_span::def_id::LOCAL_CRATE;
use rustdoc_json_types as types;
// It's important to use the FxHashMap from rustdoc_json_types here, instead of
@ -148,7 +149,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
.copied()
.filter(|(_, stability, _)| {
// Describe only target features which the user can toggle
stability.toggle_allowed().is_ok()
stability.is_toggle_permitted(sess).is_ok()
})
.map(|(name, stability, implied_features)| {
types::TargetFeature {
@ -164,7 +165,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
// Imply only target features which the user can toggle
feature_stability
.get(name)
.map(|stability| stability.toggle_allowed().is_ok())
.map(|stability| stability.is_toggle_permitted(sess).is_ok())
.unwrap_or(false)
})
.map(String::from)

View file

@ -0,0 +1,31 @@
//@ compile-flags: -Copt-level=2
#![crate_type = "lib"]
#![no_std]
// This test is paired with the arch-specific -opt3.rs test.
// The code is from https://github.com/rust-lang/rust/issues/122805.
// Ensure we do not generate the shufflevector instruction
// to avoid complicating the code.
// CHECK-LABEL: define{{.*}}void @convert(
// CHECK-NOT: shufflevector
#[no_mangle]
pub fn convert(value: [u16; 8]) -> [u8; 16] {
#[cfg(target_endian = "little")]
let bswap = u16::to_be;
#[cfg(target_endian = "big")]
let bswap = u16::to_le;
let addr16 = [
bswap(value[0]),
bswap(value[1]),
bswap(value[2]),
bswap(value[3]),
bswap(value[4]),
bswap(value[5]),
bswap(value[6]),
bswap(value[7]),
];
unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) }
}

View file

@ -1,29 +1,27 @@
//@ revisions: OPT2 OPT3 OPT3_S390X
//@[OPT2] compile-flags: -Copt-level=2
//@[OPT3] compile-flags: -C opt-level=3
// some targets don't do the opt we are looking for
//@[OPT3] only-64bit
//@[OPT3] ignore-s390x
//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13
//@[OPT3_S390X] only-s390x
//@ revisions: AARCH64 X86_64 Z13
//@ compile-flags: -Copt-level=3
//@[AARCH64] only-aarch64
//@[X86_64] only-x86_64
//@[Z13] only-s390x
//@[Z13] compile-flags: -Ctarget-cpu=z13
#![crate_type = "lib"]
#![no_std]
// This test is paired with the arch-neutral -opt2.rs test
// The code is from https://github.com/rust-lang/rust/issues/122805.
// Ensure we do not generate the shufflevector instruction
// to avoid complicating the code.
// CHECK-LABEL: define{{.*}}void @convert(
// CHECK-NOT: shufflevector
// On higher opt levels, this should just be a bswap:
// OPT3: load <8 x i16>
// OPT3-NEXT: call <8 x i16> @llvm.bswap
// OPT3-NEXT: store <8 x i16>
// OPT3-NEXT: ret void
// OPT3_S390X: load <8 x i16>
// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap
// OPT3_S390X-NEXT: store <8 x i16>
// OPT3_S390X-NEXT: ret void
// CHECK: load <8 x i16>
// CHECK-NEXT: call <8 x i16> @llvm.bswap
// CHECK-NEXT: store <8 x i16>
// CHECK-NEXT: ret void
#[no_mangle]
pub fn convert(value: [u16; 8]) -> [u8; 16] {
#[cfg(target_endian = "little")]

View file

@ -0,0 +1,29 @@
// ignore-tidy-linelength
// Test that the
// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls`
// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set.
//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk
//@ needs-llvm-components: x86
//@ compile-flags: --target x86_64-unknown-linux-gnu
//@ [enabled_retpoline] compile-flags: -Zretpoline
//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk
#![crate_type = "lib"]
#![feature(no_core, lang_items)]
#![no_core]
#[lang = "sized"]
trait Sized {}
#[no_mangle]
pub fn foo() {
// CHECK: @foo() unnamed_addr #0
// disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} }
// disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} }
// disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} }
// enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} }
// enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} }
}

View file

@ -1,7 +1,7 @@
macro_rules! morestuff {
(
<= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static
"no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)*
<= "space between most kinds of tokens" : 1 $x:ident + @ :: >>=
'static "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)*
"space inside curly brace" : { 2 a }
"no space inside empty delimiters" : () [] {}
"no space before comma or semicolon" : a, (a), { a }, a; [T; 0];

View file

@ -25,7 +25,7 @@ make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
//@ snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text()
make_macro!(morestuff
"space between most kinds of tokens": 1 $x + @ :: >>= 'static
"space between most kinds of tokens": 1 $x:ident + @ :: >>= 'static
"no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)*
"space inside curly brace": { 2 a }
"no space inside empty delimiters": () [] {}

121
tests/ui/abi/bad-custom.rs Normal file
View file

@ -0,0 +1,121 @@
//@ edition: 2021
//@ check-fail
//@ needs-asm-support
#![feature(abi_custom)]
#[unsafe(naked)]
extern "custom" fn must_be_unsafe(a: i64) -> i64 {
//~^ ERROR functions with the `"custom"` ABI must be unsafe
//~| ERROR invalid signature for `extern "custom"` function
std::arch::naked_asm!("")
}
#[unsafe(naked)]
unsafe extern "custom" fn no_parameters(a: i64) {
//~^ ERROR invalid signature for `extern "custom"` function
std::arch::naked_asm!("")
}
#[unsafe(naked)]
unsafe extern "custom" fn no_return_type() -> i64 {
//~^ ERROR invalid signature for `extern "custom"` function
std::arch::naked_asm!("")
}
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 invalid signature for `extern "custom"` function
unimplemented!()
}
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 invalid signature for `extern "custom"` function
unimplemented!()
}
}
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 invalid signature for `extern "custom"` function
unimplemented!()
}
}
impl BitwiseNot for Thing {}
trait Negate {
extern "custom" fn negate(a: i64) -> i64;
//~^ 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 invalid signature for `extern "custom"` function
-a
}
}
unsafe extern "custom" {
fn increment(a: i64) -> i64;
//~^ ERROR invalid signature for `extern "custom"` function
safe fn extern_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 {
unsafe { f(x) }
//~^ ERROR functions with the `"custom"` ABI cannot be called
}
fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
unsafe { f(x) }
//~^ ERROR functions with the `"custom"` ABI cannot be called
}
type Custom = unsafe extern "custom" fn(i64) -> i64;
fn caller_alias(f: Custom, mut x: i64) -> i64 {
unsafe { f(x) }
//~^ ERROR functions with the `"custom"` ABI cannot be called
}
#[unsafe(naked)]
const unsafe extern "custom" fn no_const_fn() {
std::arch::naked_asm!("")
//~^ ERROR inline assembly is not allowed in constant functions
}
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`
}
fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() {
//~^ ERROR expected a `Fn()` closure, found `unsafe extern "custom" fn()`
f
}
pub fn main() {
unsafe {
assert_eq!(double(21), 42);
//~^ ERROR functions with the `"custom"` ABI cannot be called
assert_eq!(unsafe { increment(41) }, 42);
//~^ ERROR functions with the `"custom"` ABI cannot be called
assert!(Thing(41).is_even());
//~^ ERROR functions with the `"custom"` ABI cannot be called
assert_eq!(Thing::bitwise_not(42), !42);
//~^ ERROR functions with the `"custom"` ABI cannot be called
}
}

View file

@ -0,0 +1,299 @@
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 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "custom" fn must_be_unsafe(a: i64) -> i64 {
| ++++++
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:7:35
|
LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= 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 {
LL + extern "custom" fn must_be_unsafe() {
|
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:14:41
|
LL | unsafe extern "custom" fn no_parameters(a: i64) {
| ^^^^^^
|
= 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) {
LL + unsafe extern "custom" fn no_parameters() {
|
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:20:47
|
LL | unsafe extern "custom" fn no_return_type() -> i64 {
| ^^^
|
= 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 {
LL + unsafe extern "custom" fn no_return_type() {
|
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:25:34
|
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= 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 {
LL + unsafe extern "custom" fn double() {
|
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:34:39
|
LL | unsafe extern "custom" fn is_even(self) -> bool {
| ^^^^ ^^^^
|
= 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 {
LL + unsafe extern "custom" fn is_even() {
|
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:42:43
|
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= 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
--> $DIR/bad-custom.rs:52:5
|
LL | extern "custom" fn negate(a: i64) -> i64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "custom" fn negate(a: i64) -> i64;
| ++++++
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:52:31
|
LL | extern "custom" fn negate(a: i64) -> i64;
| ^^^^^^ ^^^
|
= 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
--> $DIR/bad-custom.rs:58:5
|
LL | extern "custom" fn negate(a: i64) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "custom" fn negate(a: i64) -> i64 {
| ++++++
error: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:58:31
|
LL | extern "custom" fn negate(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= 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: invalid signature for `extern "custom"` function
--> $DIR/bad-custom.rs:67:18
|
LL | fn increment(a: i64) -> i64;
| ^^^^^^ ^^^
|
= 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
--> $DIR/bad-custom.rs:70:5
|
LL | safe fn extern_cannot_be_safe();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the `safe` keyword from this definition
|
LL - safe fn extern_cannot_be_safe();
LL + fn extern_cannot_be_safe();
|
error: functions with the `"custom"` ABI cannot be `async`
--> $DIR/bad-custom.rs:97:1
|
LL | async unsafe extern "custom" fn no_async_fn() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the `async` keyword from this definiton
|
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
--> $DIR/bad-custom.rs:97:1
|
LL | async unsafe extern "custom" fn no_async_fn() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: convert this to an `#[unsafe(naked)]` function
|
LL + #[unsafe(naked)]
LL | async unsafe extern "custom" fn no_async_fn() {
|
error[E0277]: expected a `Fn()` closure, found `unsafe extern "custom" fn()`
--> $DIR/bad-custom.rs:102:64
|
LL | fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() {
| ^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
LL |
LL | f
| - return type was inferred to be `unsafe extern "custom" fn()` here
|
= help: the trait `Fn()` is not implemented for `unsafe extern "custom" fn()`
= 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
--> $DIR/bad-custom.rs:25:1
|
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: convert this to an `#[unsafe(naked)]` function
|
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
--> $DIR/bad-custom.rs:34:5
|
LL | unsafe extern "custom" fn is_even(self) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: convert this to an `#[unsafe(naked)]` function
|
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
--> $DIR/bad-custom.rs:42:5
|
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: convert this to an `#[unsafe(naked)]` function
|
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
--> $DIR/bad-custom.rs:58:5
|
LL | extern "custom" fn negate(a: i64) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: convert this to an `#[unsafe(naked)]` function
|
LL + #[unsafe(naked)]
LL | extern "custom" fn negate(a: i64) -> i64 {
|
error: functions with the `"custom"` ABI cannot be called
--> $DIR/bad-custom.rs:75:14
|
LL | unsafe { f(x) }
| ^^^^
error: functions with the `"custom"` ABI cannot be called
--> $DIR/bad-custom.rs:80:14
|
LL | unsafe { f(x) }
| ^^^^
error: functions with the `"custom"` ABI cannot be called
--> $DIR/bad-custom.rs:87:14
|
LL | unsafe { f(x) }
| ^^^^
error: functions with the `"custom"` ABI cannot be called
--> $DIR/bad-custom.rs:109:20
|
LL | assert_eq!(double(21), 42);
| ^^^^^^^^^^
error: functions with the `"custom"` ABI cannot be called
--> $DIR/bad-custom.rs:112:29
|
LL | assert_eq!(unsafe { increment(41) }, 42);
| ^^^^^^^^^^^^^
error: functions with the `"custom"` ABI cannot be called
--> $DIR/bad-custom.rs:115:17
|
LL | assert!(Thing(41).is_even());
| ^^^^^^^^^^^^^^^^^^^
error: functions with the `"custom"` ABI cannot be called
--> $DIR/bad-custom.rs:118:20
|
LL | assert_eq!(Thing::bitwise_not(42), !42);
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0015]: inline assembly is not allowed in constant functions
--> $DIR/bad-custom.rs:93:5
|
LL | std::arch::naked_asm!("")
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 28 previous errors
Some errors have detailed explanations: E0015, E0277.
For more information about an error, try `rustc --explain E0015`.

88
tests/ui/abi/custom.rs Normal file
View file

@ -0,0 +1,88 @@
// Test that `extern "custom"` functions can be called from assembly, and defined using a naked
// function, and `global_asm!` with an `extern "custom"` block.
//
//@ run-pass
//@ only-x86_64
#![feature(abi_custom)]
use std::arch::{asm, global_asm, naked_asm};
#[unsafe(naked)]
unsafe extern "custom" fn double() {
naked_asm!("add rax, rax", "ret");
}
global_asm!(
// work around macOS prefixing symbols with _
" .globl {0}",
"{0}:",
" add rax, 1",
" ret",
sym increment,
);
unsafe extern "custom" {
fn increment();
}
#[repr(transparent)]
struct Thing(u64);
impl Thing {
#[unsafe(naked)]
unsafe extern "custom" fn is_even() {
naked_asm!("test al, 1", "sete al", "ret");
}
}
trait BitwiseNot {
#[unsafe(naked)]
unsafe extern "custom" fn bitwise_not() {
naked_asm!("not rax", "ret");
}
}
impl BitwiseNot for Thing {}
#[unsafe(naked)]
unsafe extern "C" fn const_generic<const N: u64>() {
naked_asm!(
"mov rax, {}",
"ret",
const N,
);
}
pub fn main() {
let mut x: u64 = 21;
unsafe { asm!("call {}", sym double, inout("rax") x) };
assert_eq!(x, 42);
let mut x: u64 = 41;
unsafe { asm!("call {}", sym increment, inout("rax") x) };
assert_eq!(x, 42);
let mut x: u8;
unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) };
assert!(x != 0);
let mut x: u64 = 42;
unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) };
assert_eq!(x, !42);
// Create and call in `asm!` an `extern "custom"` function pointer.
fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 {
unsafe { asm!("call {}", in(reg) f, inout("rax") x) };
x
}
assert_eq!(caller(double, 2), 4);
let x: u64;
unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) };
assert_eq!(x, 42);
let x: u64;
unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) };
assert_eq!(x, 84);
}

View file

@ -212,6 +212,9 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
`relax`
`relaxed-simd`
`reserve-x18`
`retpoline-external-thunk`
`retpoline-indirect-branches`
`retpoline-indirect-calls`
`rtm`
`sb`
`scq`

View file

@ -0,0 +1,51 @@
//@ add-core-stubs
//@ needs-asm-support
#![no_core]
#![feature(no_core, lang_items)]
#![crate_type = "rlib"]
extern crate minicore;
use minicore::*;
#[unsafe(naked)]
unsafe extern "custom" fn f7() {
//~^ ERROR "custom" ABI is experimental
naked_asm!("")
}
trait Tr {
extern "custom" fn m7();
//~^ ERROR "custom" ABI is experimental
//~| ERROR functions with the `"custom"` ABI must be unsafe
#[unsafe(naked)]
extern "custom" fn dm7() {
//~^ ERROR "custom" ABI is experimental
//~| ERROR functions with the `"custom"` ABI must be unsafe
naked_asm!("")
}
}
struct S;
// Methods in trait impl
impl Tr for S {
#[unsafe(naked)]
extern "custom" fn m7() {
//~^ ERROR "custom" ABI is experimental
//~| ERROR functions with the `"custom"` ABI must be unsafe
naked_asm!("")
}
}
// Methods in inherent impl
impl S {
#[unsafe(naked)]
extern "custom" fn im7() {
//~^ ERROR "custom" ABI is experimental
//~| ERROR functions with the `"custom"` ABI must be unsafe
naked_asm!("")
}
}
type A7 = extern "custom" fn(); //~ ERROR "custom" ABI is experimental
extern "custom" {} //~ ERROR "custom" ABI is experimental

View file

@ -0,0 +1,117 @@
error: functions with the `"custom"` ABI must be unsafe
--> $DIR/feature-gate-abi-custom.rs:16:5
|
LL | extern "custom" fn m7();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "custom" fn m7();
| ++++++
error: functions with the `"custom"` ABI must be unsafe
--> $DIR/feature-gate-abi-custom.rs:20:5
|
LL | extern "custom" fn dm7() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "custom" fn dm7() {
| ++++++
error: functions with the `"custom"` ABI must be unsafe
--> $DIR/feature-gate-abi-custom.rs:32:5
|
LL | extern "custom" fn m7() {
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "custom" fn m7() {
| ++++++
error: functions with the `"custom"` ABI must be unsafe
--> $DIR/feature-gate-abi-custom.rs:42:5
|
LL | extern "custom" fn im7() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "custom" fn im7() {
| ++++++
error[E0658]: the extern "custom" ABI is experimental and subject to change
--> $DIR/feature-gate-abi-custom.rs:11:15
|
LL | unsafe extern "custom" fn f7() {
| ^^^^^^^^
|
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the extern "custom" ABI is experimental and subject to change
--> $DIR/feature-gate-abi-custom.rs:16:12
|
LL | extern "custom" fn m7();
| ^^^^^^^^
|
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the extern "custom" ABI is experimental and subject to change
--> $DIR/feature-gate-abi-custom.rs:20:12
|
LL | extern "custom" fn dm7() {
| ^^^^^^^^
|
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the extern "custom" ABI is experimental and subject to change
--> $DIR/feature-gate-abi-custom.rs:32:12
|
LL | extern "custom" fn m7() {
| ^^^^^^^^
|
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the extern "custom" ABI is experimental and subject to change
--> $DIR/feature-gate-abi-custom.rs:42:12
|
LL | extern "custom" fn im7() {
| ^^^^^^^^
|
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the extern "custom" ABI is experimental and subject to change
--> $DIR/feature-gate-abi-custom.rs:49:18
|
LL | type A7 = extern "custom" fn();
| ^^^^^^^^
|
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the extern "custom" ABI is experimental and subject to change
--> $DIR/feature-gate-abi-custom.rs:51:8
|
LL | extern "custom" {}
| ^^^^^^^^
|
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -5,10 +5,6 @@ macro_rules! foo {
( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator
}
#[warn(missing_fragment_specifier)]
macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier
//~| WARN this was previously accepted
#[deprecated = "reason"]
macro_rules! deprecated {
() => {}

View file

@ -12,20 +12,6 @@ note: the lint level is defined here
LL | #[warn(meta_variable_misuse)]
| ^^^^^^^^^^^^^^^^^^^^
warning: missing fragment specifier
--> $DIR/expansion-time.rs:9:19
|
LL | macro_rules! m { ($i) => {} }
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here
--> $DIR/expansion-time.rs:8:8
|
LL | #[warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: include macro expected single expression in source
--> $DIR/expansion-time-include.rs:4:1
|
@ -33,25 +19,10 @@ LL | 2
| ^
|
note: the lint level is defined here
--> $DIR/expansion-time.rs:22:8
--> $DIR/expansion-time.rs:18:8
|
LL | #[warn(incomplete_include)]
| ^^^^^^^^^^^^^^^^^^
warning: 3 warnings emitted
Future incompatibility report: Future breakage diagnostic:
warning: missing fragment specifier
--> $DIR/expansion-time.rs:9:19
|
LL | macro_rules! m { ($i) => {} }
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here
--> $DIR/expansion-time.rs:8:8
|
LL | #[warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: 2 warnings emitted

View file

@ -4,14 +4,23 @@
// lints for changes that are not tied to an edition
#![deny(future_incompatible)]
// Error since this is a `future_incompatible` lint
macro_rules! m {
($i) => {};
//~^ ERROR missing fragment specifier
enum E { V }
trait Tr1 {
type V;
fn foo() -> Self::V;
}
impl Tr1 for E {
type V = u8;
// Error since this is a `future_incompatible` lint
fn foo() -> Self::V { 0 }
//~^ ERROR ambiguous associated item
//~| WARN this was previously accepted
}
trait Tr {
trait Tr2 {
// Warn only since this is not a `future_incompatible` lint
fn f(u8) {}
//~^ WARN anonymous parameters are deprecated

View file

@ -1,20 +1,5 @@
error: missing fragment specifier
--> $DIR/future-incompatible-lint-group.rs:9:6
|
LL | ($i) => {};
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here
--> $DIR/future-incompatible-lint-group.rs:5:9
|
LL | #![deny(future_incompatible)]
| ^^^^^^^^^^^^^^^^^^^
= note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]`
warning: anonymous parameters are deprecated and will be removed in the next edition
--> $DIR/future-incompatible-lint-group.rs:16:10
--> $DIR/future-incompatible-lint-group.rs:25:10
|
LL | fn f(u8) {}
| ^^ help: try naming the parameter or explicitly ignoring it: `_: u8`
@ -23,21 +8,30 @@ LL | fn f(u8) {}
= note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
= note: `#[warn(anonymous_parameters)]` on by default
error: aborting due to 1 previous error; 1 warning emitted
Future incompatibility report: Future breakage diagnostic:
error: missing fragment specifier
--> $DIR/future-incompatible-lint-group.rs:9:6
error: ambiguous associated item
--> $DIR/future-incompatible-lint-group.rs:18:17
|
LL | ($i) => {};
| ^^
LL | fn foo() -> Self::V { 0 }
| ^^^^^^^ help: use fully-qualified syntax: `<E as Tr1>::V`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: for more information, see issue #57644 <https://github.com/rust-lang/rust/issues/57644>
note: `V` could refer to the variant defined here
--> $DIR/future-incompatible-lint-group.rs:7:10
|
LL | enum E { V }
| ^
note: `V` could also refer to the associated type defined here
--> $DIR/future-incompatible-lint-group.rs:10:5
|
LL | type V;
| ^^^^^^
note: the lint level is defined here
--> $DIR/future-incompatible-lint-group.rs:5:9
|
LL | #![deny(future_incompatible)]
| ^^^^^^^^^^^^^^^^^^^
= note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]`
= note: `#[deny(ambiguous_associated_items)]` implied by `#[deny(future_incompatible)]`
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -1,7 +1,7 @@
#![allow(unused)]
macro_rules! m { ($i) => {} }
//~^ ERROR missing fragment specifier
//~| WARN previously accepted
macro_rules! m {
($i) => {}; //~ ERROR missing fragment specifier
}
fn main() {}

View file

@ -1,23 +1,15 @@
error: missing fragment specifier
--> $DIR/issue-39404.rs:3:19
--> $DIR/issue-39404.rs:4:6
|
LL | macro_rules! m { ($i) => {} }
| ^^
LL | ($i) => {};
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
LL | ($i:spec) => {};
| +++++
error: aborting due to 1 previous error
Future incompatibility report: Future breakage diagnostic:
error: missing fragment specifier
--> $DIR/issue-39404.rs:3:19
|
LL | macro_rules! m { ($i) => {} }
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default

View file

@ -3,8 +3,6 @@ macro_rules! test {
//~^ ERROR missing fragment
//~| ERROR missing fragment
//~| ERROR missing fragment
//~| WARN this was previously accepted
//~| WARN this was previously accepted
()
};
}

View file

@ -1,18 +1,15 @@
error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:6
|
LL | ($a, $b) => {
| ^^
error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:6
|
LL | ($a, $b) => {
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
LL | ($a:spec, $b) => {
| +++++
error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:10
@ -20,30 +17,18 @@ error: missing fragment specifier
LL | ($a, $b) => {
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
LL | ($a, $b:spec) => {
| +++++
error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:6
|
LL | ($a, $b) => {
| ^^
error: aborting due to 3 previous errors
Future incompatibility report: Future breakage diagnostic:
error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:6
|
LL | ($a, $b) => {
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default
Future breakage diagnostic:
error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:10
|
LL | ($a, $b) => {
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default

View file

@ -1,10 +1,8 @@
//@ compile-flags: -Zdeduplicate-diagnostics=yes
macro_rules! m {
($name) => {}
//~^ ERROR missing fragment
//~| ERROR missing fragment
//~| WARN this was previously accepted
($name) => {}; //~ ERROR missing fragment
//~| ERROR missing fragment
}
fn main() {

View file

@ -1,29 +1,21 @@
error: missing fragment specifier
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
LL | ($name) => {}
LL | ($name) => {};
| ^^^^^
|
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
LL | ($name:spec) => {};
| +++++
error: missing fragment specifier
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
LL | ($name) => {}
LL | ($name) => {};
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default
error: aborting due to 2 previous errors
Future incompatibility report: Future breakage diagnostic:
error: missing fragment specifier
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
LL | ($name) => {}
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default

View file

@ -1,85 +0,0 @@
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:8:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^
warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:8:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:5:9
|
LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:18:7
|
LL | ( $name ) => {};
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:25:7
|
LL | ( $name ) => {};
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
error: aborting due to 1 previous error; 3 warnings emitted
Future incompatibility report: Future breakage diagnostic:
warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:8:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:5:9
|
LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Future breakage diagnostic:
warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:18:7
|
LL | ( $name ) => {};
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:5:9
|
LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Future breakage diagnostic:
warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:25:7
|
LL | ( $name ) => {};
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:5:9
|
LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,31 +1,17 @@
//@ revisions: e2015 e2024
//@[e2015] edition:2015
//@[e2024] edition:2024
#![warn(missing_fragment_specifier)]
//! Ensure that macros produce an error if fragment specifiers are missing.
macro_rules! used_arm {
( $( any_token $field_rust_type )* ) => {};
//[e2015]~^ ERROR missing fragment
//[e2015]~| WARN missing fragment
//[e2015]~| WARN this was previously accepted
//[e2024]~^^^^ ERROR missing fragment
//[e2024]~| ERROR missing fragment
( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment
//~| ERROR missing fragment
}
macro_rules! used_macro_unused_arm {
() => {};
( $name ) => {};
//[e2015]~^ WARN missing fragment
//[e2015]~| WARN this was previously accepted
//[e2024]~^^^ ERROR missing fragment
( $name ) => {}; //~ ERROR missing fragment
}
macro_rules! unused_macro {
( $name ) => {};
//[e2015]~^ WARN missing fragment
//[e2015]~| WARN this was previously accepted
//[e2024]~^^^ ERROR missing fragment
( $name ) => {}; //~ ERROR missing fragment
}
fn main() {

View file

@ -1,10 +1,10 @@
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:8:20
--> $DIR/macro-missing-fragment.rs:4:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^
|
= note: fragment specifiers must be specified in the 2024 edition
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
@ -12,12 +12,12 @@ LL | ( $( any_token $field_rust_type:spec )* ) => {};
| +++++
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:18:7
--> $DIR/macro-missing-fragment.rs:10:7
|
LL | ( $name ) => {};
| ^^^^^
|
= note: fragment specifiers must be specified in the 2024 edition
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
@ -25,12 +25,12 @@ LL | ( $name:spec ) => {};
| +++++
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:25:7
--> $DIR/macro-missing-fragment.rs:14:7
|
LL | ( $name ) => {};
| ^^^^^
|
= note: fragment specifiers must be specified in the 2024 edition
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
@ -38,7 +38,7 @@ LL | ( $name:spec ) => {};
| +++++
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:8:20
--> $DIR/macro-missing-fragment.rs:4:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^

View file

@ -2,7 +2,6 @@ macro_rules! foo {
{ $+ } => { //~ ERROR expected identifier, found `+`
//~^ ERROR missing fragment specifier
//~| ERROR missing fragment specifier
//~| WARN this was previously accepted
$(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
}
}

View file

@ -5,7 +5,7 @@ LL | { $+ } => {
| ^
error: expected one of: `*`, `+`, or `?`
--> $DIR/issue-33569.rs:6:13
--> $DIR/issue-33569.rs:5:13
|
LL | $(x)(y)
| ^^^
@ -15,27 +15,19 @@ error: missing fragment specifier
|
LL | { $+ } => {
| ^
|
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: try adding a specifier here
|
LL | { $+:spec } => {
| +++++
error: missing fragment specifier
--> $DIR/issue-33569.rs:2:8
|
LL | { $+ } => {
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default
error: aborting due to 4 previous errors
Future incompatibility report: Future breakage diagnostic:
error: missing fragment specifier
--> $DIR/issue-33569.rs:2:8
|
LL | { $+ } => {
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
= note: `#[deny(missing_fragment_specifier)]` on by default

View file

@ -9,6 +9,7 @@ avr-interrupt
avr-non-blocking-interrupt
cdecl
cdecl-unwind
custom
efiapi
fastcall
fastcall-unwind

View file

@ -0,0 +1,7 @@
warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `x86-retpoline` target modifier flag instead
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 1 warning emitted

View file

@ -0,0 +1,7 @@
warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 1 warning emitted

View file

@ -0,0 +1,7 @@
warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 1 warning emitted

View file

@ -0,0 +1,7 @@
warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
|
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
warning: 1 warning emitted

View file

@ -0,0 +1,23 @@
//@ revisions: by_flag by_feature1 by_feature2 by_feature3
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
//@ needs-llvm-components: x86
//@ [by_flag]compile-flags: -Zretpoline
//@ [by_feature1]compile-flags: -Ctarget-feature=+retpoline-external-thunk
//@ [by_feature2]compile-flags: -Ctarget-feature=+retpoline-indirect-branches
//@ [by_feature3]compile-flags: -Ctarget-feature=+retpoline-indirect-calls
//@ [by_flag]build-pass
// For now this is just a warning.
//@ [by_feature1]build-pass
//@ [by_feature2]build-pass
//@ [by_feature3]build-pass
#![feature(no_core, lang_items)]
#![no_std]
#![no_core]
#[lang = "sized"]
pub trait Sized {}
//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead