Skip to content

Commit 1278dad

Browse files
committed
Auto merge of rust-lang#133433 - matthiaskrgr:rollup-lfa3wp1, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - rust-lang#131523 (Fix asm goto with outputs and move it to a separate feature gate) - rust-lang#131664 (Support input/output in vector registers of s390x inline assembly (under asm_experimental_reg feature)) - rust-lang#132432 (Add a test to verify that libstd doesn't use protected symbols) - rust-lang#132502 (Document possibility to set core features in example config.toml) - rust-lang#132529 (ci(triagebot): add more top-level files to A-meta) - rust-lang#132533 (Add BorrowedBuf::into_filled{,_mut} methods to allow returning buffer with original lifetime) - rust-lang#132803 (Fix broken url) - rust-lang#132982 (alloc: fix `Allocator` method names in `alloc` free function docs) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 67a8c64 + d2590e0 commit 1278dad

File tree

34 files changed

+1655
-198
lines changed

34 files changed

+1655
-198
lines changed

compiler/rustc_ast_lowering/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ ast_lowering_register2 = register `{$reg2_name}`
152152
153153
ast_lowering_register_class_only_clobber =
154154
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
155+
ast_lowering_register_class_only_clobber_stable =
156+
register class `{$reg_class_name}` can only be used as a clobber in stable
155157
156158
ast_lowering_register_conflict =
157159
register `{$reg1_name}` conflicts with register `{$reg2_name}`
@@ -181,6 +183,8 @@ ast_lowering_underscore_expr_lhs_assign =
181183
.label = `_` not allowed here
182184
183185
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
186+
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
187+
using both label and output operands for inline assembly is unstable
184188
ast_lowering_unstable_inline_assembly_label_operands =
185189
label operands for inline assembly are unstable
186190
ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable

compiler/rustc_ast_lowering/src/asm.rs

+61-15
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use super::errors::{
1717
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
1818
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
1919
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
20-
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
20+
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable,
21+
RegisterConflict,
2122
};
2223
use crate::{
2324
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
@@ -61,6 +62,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
6162
.emit();
6263
}
6364
}
65+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
6466
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
6567
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
6668
&& !self.tcx.sess.opts.actually_rustdoc
@@ -239,15 +241,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
239241
}
240242
}
241243
InlineAsmOperand::Label { block } => {
242-
if !self.tcx.features().asm_goto() {
243-
feature_err(
244-
sess,
245-
sym::asm_goto,
246-
*op_sp,
247-
fluent::ast_lowering_unstable_inline_assembly_label_operands,
248-
)
249-
.emit();
250-
}
251244
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
252245
}
253246
};
@@ -333,11 +326,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
333326
// means that we disallow passing a value in/out of the asm and
334327
// require that the operand name an explicit register, not a
335328
// register class.
336-
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
337-
self.dcx().emit_err(RegisterClassOnlyClobber {
338-
op_span: op_sp,
339-
reg_class_name: reg_class.name(),
340-
});
329+
if reg_class.is_clobber_only(asm_arch.unwrap(), allow_experimental_reg)
330+
&& !op.is_clobber()
331+
{
332+
if allow_experimental_reg || reg_class.is_clobber_only(asm_arch.unwrap(), true)
333+
{
334+
// always clobber-only
335+
self.dcx().emit_err(RegisterClassOnlyClobber {
336+
op_span: op_sp,
337+
reg_class_name: reg_class.name(),
338+
});
339+
} else {
340+
// clobber-only in stable
341+
self.tcx
342+
.sess
343+
.create_feature_err(
344+
RegisterClassOnlyClobberStable {
345+
op_span: op_sp,
346+
reg_class_name: reg_class.name(),
347+
},
348+
sym::asm_experimental_reg,
349+
)
350+
.emit();
351+
}
341352
continue;
342353
}
343354

@@ -466,6 +477,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
466477
}
467478
}
468479

480+
// Feature gate checking for asm goto.
481+
if let Some((_, op_sp)) =
482+
operands.iter().find(|(op, _)| matches!(op, hir::InlineAsmOperand::Label { .. }))
483+
{
484+
if !self.tcx.features().asm_goto() {
485+
feature_err(
486+
sess,
487+
sym::asm_goto,
488+
*op_sp,
489+
fluent::ast_lowering_unstable_inline_assembly_label_operands,
490+
)
491+
.emit();
492+
}
493+
494+
// In addition, check if an output operand is used.
495+
// This is gated behind an additional feature.
496+
let output_operand_used = operands.iter().any(|(op, _)| {
497+
matches!(
498+
op,
499+
hir::InlineAsmOperand::Out { expr: Some(_), .. }
500+
| hir::InlineAsmOperand::InOut { .. }
501+
| hir::InlineAsmOperand::SplitInOut { out_expr: Some(_), .. }
502+
)
503+
});
504+
if output_operand_used && !self.tcx.features().asm_goto_with_outputs() {
505+
feature_err(
506+
sess,
507+
sym::asm_goto_with_outputs,
508+
*op_sp,
509+
fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs,
510+
)
511+
.emit();
512+
}
513+
}
514+
469515
let operands = self.arena.alloc_from_iter(operands);
470516
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
471517
let template_strs = self.arena.alloc_from_iter(

compiler/rustc_ast_lowering/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ pub(crate) struct RegisterClassOnlyClobber {
279279
pub reg_class_name: Symbol,
280280
}
281281

282+
#[derive(Diagnostic)]
283+
#[diag(ast_lowering_register_class_only_clobber_stable)]
284+
pub(crate) struct RegisterClassOnlyClobberStable {
285+
#[primary_span]
286+
pub op_span: Span,
287+
pub reg_class_name: Symbol,
288+
}
289+
282290
#[derive(Diagnostic)]
283291
#[diag(ast_lowering_register_conflict)]
284292
pub(crate) struct RegisterConflict<'a> {

compiler/rustc_builtin_macros/src/asm.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,10 @@ pub fn parse_asm_args<'a>(
300300
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
301301
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
302302
}
303-
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
303+
if args.options.contains(ast::InlineAsmOptions::NORETURN)
304+
&& !outputs_sp.is_empty()
305+
&& labels_sp.is_empty()
306+
{
304307
let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
305308
// Bail out now since this is likely to confuse MIR
306309
return Err(err);

compiler/rustc_codegen_cranelift/src/inline_asm.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
462462
let mut slots_output = vec![None; self.operands.len()];
463463

464464
let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| {
465-
let reg_size =
466-
reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap();
465+
let reg_size = reg_class
466+
.supported_types(self.arch, true)
467+
.iter()
468+
.map(|(ty, _)| ty.size())
469+
.max()
470+
.unwrap();
467471
let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap();
468472
let offset = slot_size.align_to(align);
469473
*slot_size = offset + reg_size;

compiler/rustc_codegen_gcc/src/asm.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
186186
// `clobber_abi` can add lots of clobbers that are not supported by the target,
187187
// such as AVX-512 registers, so we just ignore unsupported registers
188188
let is_target_supported =
189-
reg.reg_class().supported_types(asm_arch).iter().any(
189+
reg.reg_class().supported_types(asm_arch, true).iter().any(
190190
|&(_, feature)| {
191191
if let Some(feature) = feature {
192192
self.tcx
@@ -683,9 +683,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
683683
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
684684
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
685685
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
686-
InlineAsmRegClass::S390x(
687-
S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg,
688-
) => {
686+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
687+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
689688
unreachable!("clobber-only")
690689
}
691690
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
@@ -766,7 +765,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
766765
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
767766
) => cx.type_i32(),
768767
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
769-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
768+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
769+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
770770
unreachable!("clobber-only")
771771
}
772772
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),

compiler/rustc_codegen_llvm/src/asm.rs

+31-21
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
4545
match *op {
4646
InlineAsmOperandRef::Out { reg, late, place } => {
4747
let is_target_supported = |reg_class: InlineAsmRegClass| {
48-
for &(_, feature) in reg_class.supported_types(asm_arch) {
48+
for &(_, feature) in reg_class.supported_types(asm_arch, true) {
4949
if let Some(feature) = feature {
5050
if self
5151
.tcx
@@ -85,7 +85,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
8585
}
8686
continue;
8787
} else if !is_target_supported(reg.reg_class())
88-
|| reg.reg_class().is_clobber_only(asm_arch)
88+
|| reg.reg_class().is_clobber_only(asm_arch, true)
8989
{
9090
// We turn discarded outputs into clobber constraints
9191
// if the target feature needed by the register class is
@@ -342,24 +342,32 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
342342
}
343343
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
344344

345-
// Switch to the 'normal' basic block if we did an `invoke` instead of a `call`
346-
if let Some(dest) = dest {
347-
self.switch_to_block(dest);
348-
}
345+
// Write results to outputs. We need to do this for all possible control flow.
346+
//
347+
// Note that `dest` maybe populated with unreachable_block when asm goto with outputs
348+
// is used (because we need to codegen callbr which always needs a destination), so
349+
// here we use the NORETURN option to determine if `dest` should be used.
350+
for block in (if options.contains(InlineAsmOptions::NORETURN) { None } else { Some(dest) })
351+
.into_iter()
352+
.chain(labels.iter().copied().map(Some))
353+
{
354+
if let Some(block) = block {
355+
self.switch_to_block(block);
356+
}
349357

350-
// Write results to outputs
351-
for (idx, op) in operands.iter().enumerate() {
352-
if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
353-
| InlineAsmOperandRef::InOut { reg, out_place: Some(place), .. } = *op
354-
{
355-
let value = if output_types.len() == 1 {
356-
result
357-
} else {
358-
self.extract_value(result, op_idx[&idx] as u64)
359-
};
360-
let value =
361-
llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
362-
OperandValue::Immediate(value).store(self, place);
358+
for (idx, op) in operands.iter().enumerate() {
359+
if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
360+
| InlineAsmOperandRef::InOut { reg, out_place: Some(place), .. } = *op
361+
{
362+
let value = if output_types.len() == 1 {
363+
result
364+
} else {
365+
self.extract_value(result, op_idx[&idx] as u64)
366+
};
367+
let value =
368+
llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
369+
OperandValue::Immediate(value).store(self, place);
370+
}
363371
}
364372
}
365373
}
@@ -678,7 +686,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
678686
S390x(S390xInlineAsmRegClass::reg) => "r",
679687
S390x(S390xInlineAsmRegClass::reg_addr) => "a",
680688
S390x(S390xInlineAsmRegClass::freg) => "f",
681-
S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
689+
S390x(S390xInlineAsmRegClass::vreg) => "v",
690+
S390x(S390xInlineAsmRegClass::areg) => {
682691
unreachable!("clobber-only")
683692
}
684693
Sparc(SparcInlineAsmRegClass::reg) => "r",
@@ -844,7 +853,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
844853
Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
845854
S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(),
846855
S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
847-
S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
856+
S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
857+
S390x(S390xInlineAsmRegClass::areg) => {
848858
unreachable!("clobber-only")
849859
}
850860
Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),

compiler/rustc_feature/src/unstable.rs

+4
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,12 @@ declare_features! (
376376
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
377377
/// Enables experimental inline assembly support for additional architectures.
378378
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
379+
/// Enables experimental register support in inline assembly.
380+
(unstable, asm_experimental_reg, "CURRENT_RUSTC_VERSION", Some(133416)),
379381
/// Allows using `label` operands in inline assembly.
380382
(unstable, asm_goto, "1.78.0", Some(119364)),
383+
/// Allows using `label` operands in inline assembly together with output operands.
384+
(unstable, asm_goto_with_outputs, "CURRENT_RUSTC_VERSION", Some(119364)),
381385
/// Allows the `may_unwind` option in inline assembly.
382386
(unstable, asm_unwind, "1.58.0", Some(93334)),
383387
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.

compiler/rustc_hir_analysis/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is
431431
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
432432
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
433433
434+
hir_analysis_register_type_unstable =
435+
type `{$ty}` cannot be used with this register class in stable
436+
434437
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
435438
436439
hir_analysis_return_type_notation_equality_bound =

compiler/rustc_hir_analysis/src/check/intrinsicck.rs

+27-11
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ use rustc_hir::{self as hir, LangItem};
77
use rustc_middle::bug;
88
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
99
use rustc_session::lint;
10-
use rustc_span::Symbol;
1110
use rustc_span::def_id::LocalDefId;
11+
use rustc_span::{Symbol, sym};
1212
use rustc_target::asm::{
1313
InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
1414
};
1515

16+
use crate::errors::RegisterTypeUnstable;
17+
1618
pub struct InlineAsmCtxt<'a, 'tcx> {
1719
tcx: TyCtxt<'tcx>,
1820
typing_env: ty::TypingEnv<'tcx>,
@@ -218,17 +220,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
218220
// Check the type against the list of types supported by the selected
219221
// register class.
220222
let asm_arch = self.tcx.sess.asm_arch.unwrap();
223+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
221224
let reg_class = reg.reg_class();
222-
let supported_tys = reg_class.supported_types(asm_arch);
225+
let supported_tys = reg_class.supported_types(asm_arch, allow_experimental_reg);
223226
let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
224-
let msg = format!("type `{ty}` cannot be used with this register class");
225-
let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
226-
let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect();
227-
err.note(format!(
228-
"register class `{}` supports these types: {}",
229-
reg_class.name(),
230-
supported_tys.join(", "),
231-
));
227+
let mut err = if !allow_experimental_reg
228+
&& reg_class.supported_types(asm_arch, true).iter().any(|&(t, _)| t == asm_ty)
229+
{
230+
self.tcx.sess.create_feature_err(
231+
RegisterTypeUnstable { span: expr.span, ty },
232+
sym::asm_experimental_reg,
233+
)
234+
} else {
235+
let msg = format!("type `{ty}` cannot be used with this register class");
236+
let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
237+
let supported_tys: Vec<_> =
238+
supported_tys.iter().map(|(t, _)| t.to_string()).collect();
239+
err.note(format!(
240+
"register class `{}` supports these types: {}",
241+
reg_class.name(),
242+
supported_tys.join(", "),
243+
));
244+
err
245+
};
232246
if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) {
233247
err.help(format!("consider using the `{}` register class instead", suggest.name()));
234248
}
@@ -313,6 +327,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
313327
self.tcx.dcx().delayed_bug("target architecture does not support asm");
314328
return;
315329
};
330+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
316331
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
317332
// Validate register classes against currently enabled target
318333
// features. We check that at least one type is available for
@@ -352,7 +367,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
352367
if let InlineAsmRegClass::Err = reg_class {
353368
continue;
354369
}
355-
for &(_, feature) in reg_class.supported_types(asm_arch) {
370+
for &(_, feature) in reg_class.supported_types(asm_arch, allow_experimental_reg)
371+
{
356372
match feature {
357373
Some(feature) => {
358374
if target_features.contains(&feature) {

compiler/rustc_hir_analysis/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1708,3 +1708,11 @@ pub(crate) struct CmseEntryGeneric {
17081708
#[primary_span]
17091709
pub span: Span,
17101710
}
1711+
1712+
#[derive(Diagnostic)]
1713+
#[diag(hir_analysis_register_type_unstable)]
1714+
pub(crate) struct RegisterTypeUnstable<'a> {
1715+
#[primary_span]
1716+
pub span: Span,
1717+
pub ty: Ty<'a>,
1718+
}

0 commit comments

Comments
 (0)