Skip to content

Commit ee7935c

Browse files
committed
Auto merge of #142409 - matthiaskrgr:rollup-cnag5so, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #138016 (Added `Clone` implementation for `ChunkBy`) - #140770 (add `extern "custom"` functions) - #141162 (refactor `AttributeGate` and `rustc_attr!` to emit notes during feature checking) - #141474 (Add `ParseMode::Diagnostic` and fix multiline spans in diagnostic attribute lints) - #141947 (Specify that "option-like" enums must be `#[repr(Rust)]` to be ABI-compatible with their non-1ZST field.) - #142252 (Improve clarity of `core::sync::atomic` docs about "Considerations" in regards to CAS operations) - #142337 (miri: add flag to suppress float non-determinism) - #142353 (compiler: Ease off the accelerator on `unsupported_calling_conventions`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 6c8138d + a8d9a9f commit ee7935c

File tree

90 files changed

+1899
-953
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+1899
-953
lines changed

compiler/rustc_abi/src/canon_abi.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub enum CanonAbi {
2828
Rust,
2929
RustCold,
3030

31+
/// An ABI that rustc does not know how to call or define.
32+
Custom,
33+
3134
/// ABIs relevant to 32-bit Arm targets
3235
Arm(ArmCall),
3336
/// ABI relevant to GPUs: the entry point for a GPU kernel
@@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
5760
CanonAbi::C => ExternAbi::C { unwind: false },
5861
CanonAbi::Rust => ExternAbi::Rust,
5962
CanonAbi::RustCold => ExternAbi::RustCold,
63+
CanonAbi::Custom => ExternAbi::Custom,
6064
CanonAbi::Arm(arm_call) => match arm_call {
6165
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
6266
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,

compiler/rustc_abi/src/extern_abi.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ pub enum ExternAbi {
4040
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
4141
Unadjusted,
4242

43+
/// An ABI that rustc does not know how to call or define. Functions with this ABI can
44+
/// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
45+
/// be called from inline assembly.
46+
Custom,
47+
4348
/// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
4449
/// and only valid on platforms that have a UEFI standard
4550
EfiApi,
@@ -141,6 +146,7 @@ abi_impls! {
141146
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
142147
Cdecl { unwind: false } =><= "cdecl",
143148
Cdecl { unwind: true } =><= "cdecl-unwind",
149+
Custom =><= "custom",
144150
EfiApi =><= "efiapi",
145151
Fastcall { unwind: false } =><= "fastcall",
146152
Fastcall { unwind: true } =><= "fastcall-unwind",

compiler/rustc_ast/src/ast.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3520,6 +3520,38 @@ impl FnHeader {
35203520
|| matches!(constness, Const::Yes(_))
35213521
|| !matches!(ext, Extern::None)
35223522
}
3523+
3524+
/// Return a span encompassing the header, or none if all options are default.
3525+
pub fn span(&self) -> Option<Span> {
3526+
fn append(a: &mut Option<Span>, b: Span) {
3527+
*a = match a {
3528+
None => Some(b),
3529+
Some(x) => Some(x.to(b)),
3530+
}
3531+
}
3532+
3533+
let mut full_span = None;
3534+
3535+
match self.safety {
3536+
Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
3537+
Safety::Default => {}
3538+
};
3539+
3540+
if let Some(coroutine_kind) = self.coroutine_kind {
3541+
append(&mut full_span, coroutine_kind.span());
3542+
}
3543+
3544+
if let Const::Yes(span) = self.constness {
3545+
append(&mut full_span, span);
3546+
}
3547+
3548+
match self.ext {
3549+
Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
3550+
Extern::None => {}
3551+
}
3552+
3553+
full_span
3554+
}
35233555
}
35243556

35253557
impl Default for FnHeader {

compiler/rustc_ast_lowering/src/stability.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
134134
feature: sym::cmse_nonsecure_entry,
135135
explain: GateReason::Experimental,
136136
}),
137+
ExternAbi::Custom => {
138+
Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
139+
}
137140
}
138141
}

compiler/rustc_ast_passes/messages.ftl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
ast_passes_abi_custom_coroutine =
2+
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
3+
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
4+
5+
ast_passes_abi_custom_invalid_signature =
6+
invalid signature for `extern "custom"` function
7+
.note = functions with the `"custom"` ABI cannot have any parameters or return type
8+
.suggestion = remove the parameters and return type
9+
10+
ast_passes_abi_custom_safe_foreign_function =
11+
foreign functions with the `"custom"` ABI cannot be safe
12+
.suggestion = remove the `safe` keyword from this definition
13+
14+
ast_passes_abi_custom_safe_function =
15+
functions with the `"custom"` ABI must be unsafe
16+
.suggestion = add the `unsafe` keyword to this definition
17+
118
ast_passes_assoc_const_without_body =
219
associated constant in `impl` without body
320
.suggestion = provide a definition for the constant

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
1919
use std::mem;
2020
use std::ops::{Deref, DerefMut};
21+
use std::str::FromStr;
2122

2223
use itertools::{Either, Itertools};
2324
use rustc_abi::ExternAbi;
@@ -81,6 +82,7 @@ struct AstValidator<'a> {
8182

8283
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
8384
extern_mod_safety: Option<Safety>,
85+
extern_mod_abi: Option<ExternAbi>,
8486

8587
lint_node_id: NodeId,
8688

@@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
121123
self.outer_trait_or_trait_impl = old;
122124
}
123125

124-
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
125-
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
126+
fn with_in_extern_mod(
127+
&mut self,
128+
extern_mod_safety: Safety,
129+
abi: Option<ExternAbi>,
130+
f: impl FnOnce(&mut Self),
131+
) {
132+
let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
133+
let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
126134
f(self);
127-
self.extern_mod_safety = old;
135+
self.extern_mod_safety = old_safety;
136+
self.extern_mod_abi = old_abi;
128137
}
129138

130139
fn with_tilde_const(
@@ -370,6 +379,65 @@ impl<'a> AstValidator<'a> {
370379
}
371380
}
372381

382+
/// An `extern "custom"` function must be unsafe, and must not have any parameters or return
383+
/// type.
384+
fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
385+
let dcx = self.dcx();
386+
387+
// An `extern "custom"` function must be unsafe.
388+
match sig.header.safety {
389+
Safety::Unsafe(_) => { /* all good */ }
390+
Safety::Safe(safe_span) => {
391+
let safe_span =
392+
self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span));
393+
dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
394+
}
395+
Safety::Default => match ctxt {
396+
FnCtxt::Foreign => { /* all good */ }
397+
FnCtxt::Free | FnCtxt::Assoc(_) => {
398+
self.dcx().emit_err(errors::AbiCustomSafeFunction {
399+
span: sig.span,
400+
unsafe_span: sig.span.shrink_to_lo(),
401+
});
402+
}
403+
},
404+
}
405+
406+
// An `extern "custom"` function cannot be `async` and/or `gen`.
407+
if let Some(coroutine_kind) = sig.header.coroutine_kind {
408+
let coroutine_kind_span = self
409+
.sess
410+
.psess
411+
.source_map()
412+
.span_until_non_whitespace(coroutine_kind.span().to(sig.span));
413+
414+
self.dcx().emit_err(errors::AbiCustomCoroutine {
415+
span: sig.span,
416+
coroutine_kind_span,
417+
coroutine_kind_str: coroutine_kind.as_str(),
418+
});
419+
}
420+
421+
// An `extern "custom"` function must not have any parameters or return type.
422+
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
423+
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
424+
spans.push(ret_ty.span);
425+
}
426+
427+
if !spans.is_empty() {
428+
let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
429+
let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
430+
let padding = if header_span.is_empty() { "" } else { " " };
431+
432+
self.dcx().emit_err(errors::AbiCustomInvalidSignature {
433+
spans,
434+
symbol: ident.name,
435+
suggestion_span,
436+
padding,
437+
});
438+
}
439+
}
440+
373441
/// This ensures that items can only be `unsafe` (or unmarked) outside of extern
374442
/// blocks.
375443
///
@@ -1005,7 +1073,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10051073
if abi.is_none() {
10061074
self.handle_missing_abi(*extern_span, item.id);
10071075
}
1008-
self.with_in_extern_mod(*safety, |this| {
1076+
1077+
let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok());
1078+
self.with_in_extern_mod(*safety, extern_abi, |this| {
10091079
visit::walk_item(this, item);
10101080
});
10111081
self.extern_mod_span = old_item;
@@ -1145,6 +1215,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11451215
self.check_foreign_fn_bodyless(*ident, body.as_deref());
11461216
self.check_foreign_fn_headerless(sig.header);
11471217
self.check_foreign_item_ascii_only(*ident);
1218+
if self.extern_mod_abi == Some(ExternAbi::Custom) {
1219+
self.check_custom_abi(FnCtxt::Foreign, ident, sig);
1220+
}
11481221
}
11491222
ForeignItemKind::TyAlias(box TyAlias {
11501223
defaultness,
@@ -1352,6 +1425,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13521425
self.check_item_safety(span, safety);
13531426
}
13541427

1428+
if let FnKind::Fn(ctxt, _, fun) = fk
1429+
&& let Extern::Explicit(str_lit, _) = fun.sig.header.ext
1430+
&& let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str())
1431+
{
1432+
self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
1433+
}
1434+
13551435
self.check_c_variadic_type(fk);
13561436

13571437
// Functions cannot both be `const async` or `const gen`
@@ -1703,6 +1783,7 @@ pub fn check_crate(
17031783
outer_impl_trait_span: None,
17041784
disallow_tilde_const: Some(TildeConstReason::Item),
17051785
extern_mod_safety: None,
1786+
extern_mod_abi: None,
17061787
lint_node_id: CRATE_NODE_ID,
17071788
is_sdylib_interface,
17081789
lint_buffer: lints,

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,3 +824,67 @@ pub(crate) struct MissingAbi {
824824
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
825825
pub span: Span,
826826
}
827+
828+
#[derive(Diagnostic)]
829+
#[diag(ast_passes_abi_custom_safe_foreign_function)]
830+
pub(crate) struct AbiCustomSafeForeignFunction {
831+
#[primary_span]
832+
pub span: Span,
833+
834+
#[suggestion(
835+
ast_passes_suggestion,
836+
applicability = "maybe-incorrect",
837+
code = "",
838+
style = "verbose"
839+
)]
840+
pub safe_span: Span,
841+
}
842+
843+
#[derive(Diagnostic)]
844+
#[diag(ast_passes_abi_custom_safe_function)]
845+
pub(crate) struct AbiCustomSafeFunction {
846+
#[primary_span]
847+
pub span: Span,
848+
849+
#[suggestion(
850+
ast_passes_suggestion,
851+
applicability = "maybe-incorrect",
852+
code = "unsafe ",
853+
style = "verbose"
854+
)]
855+
pub unsafe_span: Span,
856+
}
857+
858+
#[derive(Diagnostic)]
859+
#[diag(ast_passes_abi_custom_coroutine)]
860+
pub(crate) struct AbiCustomCoroutine {
861+
#[primary_span]
862+
pub span: Span,
863+
864+
#[suggestion(
865+
ast_passes_suggestion,
866+
applicability = "maybe-incorrect",
867+
code = "",
868+
style = "verbose"
869+
)]
870+
pub coroutine_kind_span: Span,
871+
pub coroutine_kind_str: &'static str,
872+
}
873+
874+
#[derive(Diagnostic)]
875+
#[diag(ast_passes_abi_custom_invalid_signature)]
876+
#[note]
877+
pub(crate) struct AbiCustomInvalidSignature {
878+
#[primary_span]
879+
pub spans: Vec<Span>,
880+
881+
#[suggestion(
882+
ast_passes_suggestion,
883+
applicability = "maybe-incorrect",
884+
code = "{padding}fn {symbol}()",
885+
style = "verbose"
886+
)]
887+
pub suggestion_span: Span,
888+
pub symbol: Symbol,
889+
pub padding: &'static str,
890+
}

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ macro_rules! gate_alt {
3636
feature_err(&$visitor.sess, $name, $span, $explain).emit();
3737
}
3838
}};
39+
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
40+
if !$has_feature && !$span.allows_unstable($name) {
41+
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
42+
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
43+
for note in $notes {
44+
diag.note(*note);
45+
}
46+
diag.emit();
47+
}
48+
}};
3949
}
4050

4151
/// The case involving a multispan.
@@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
154164
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
155165
// Check feature gates for built-in attributes.
156166
if let Some(BuiltinAttribute {
157-
gate: AttributeGate::Gated(_, name, descr, has_feature),
167+
gate: AttributeGate::Gated { feature, message, check, notes, .. },
158168
..
159169
}) = attr_info
160170
{
161-
gate_alt!(self, has_feature(self.features), *name, attr.span, *descr);
171+
gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
162172
}
163173
// Check unstable flavors of the `#[doc]` attribute.
164174
if attr.has_name(sym::doc) {

compiler/rustc_codegen_cranelift/src/abi/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv(
5151
CanonAbi::Rust | CanonAbi::C => default_call_conv,
5252
CanonAbi::RustCold => CallConv::Cold,
5353

54+
// Functions with this calling convention can only be called from assembly, but it is
55+
// possible to declare an `extern "custom"` block, so the backend still needs a calling
56+
// convention for declaring foreign functions.
57+
CanonAbi::Custom => default_call_conv,
58+
5459
CanonAbi::X86(x86_call) => match x86_call {
5560
X86Call::SysV64 => CallConv::SystemV,
5661
X86Call::Win64 => CallConv::WindowsFastcall,

compiler/rustc_codegen_gcc/src/abi.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
239239
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
240240
let attribute = match conv {
241241
CanonAbi::C | CanonAbi::Rust => return None,
242+
CanonAbi::RustCold => FnAttribute::Cold,
243+
// Functions with this calling convention can only be called from assembly, but it is
244+
// possible to declare an `extern "custom"` block, so the backend still needs a calling
245+
// convention for declaring foreign functions.
246+
CanonAbi::Custom => return None,
242247
CanonAbi::Arm(arm_call) => match arm_call {
243248
ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
244249
ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
245250
ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
246251
},
247-
CanonAbi::RustCold => FnAttribute::Cold,
248252
CanonAbi::GpuKernel => {
249253
if arch == "amdgpu" {
250254
FnAttribute::GcnAmdGpuHsaKernel

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,10 @@ impl llvm::CallConv {
649649
match conv {
650650
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
651651
CanonAbi::RustCold => llvm::PreserveMost,
652+
// Functions with this calling convention can only be called from assembly, but it is
653+
// possible to declare an `extern "custom"` block, so the backend still needs a calling
654+
// convention for declaring foreign functions.
655+
CanonAbi::Custom => llvm::CCallConv,
652656
CanonAbi::GpuKernel => {
653657
if arch == "amdgpu" {
654658
llvm::AmdgpuKernel

0 commit comments

Comments
 (0)