Skip to content

Commit

Permalink
Auto merge of #133433 - matthiaskrgr:rollup-lfa3wp1, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 8 pull requests

Successful merges:

 - #131523 (Fix asm goto with outputs and move it to a separate feature gate)
 - #131664 (Support input/output in vector registers of s390x inline assembly (under asm_experimental_reg feature))
 - #132432 (Add a test to verify that libstd doesn't use protected symbols)
 - #132502 (Document possibility to set core features in example config.toml)
 - #132529 (ci(triagebot): add more top-level files to A-meta)
 - #132533 (Add BorrowedBuf::into_filled{,_mut} methods to allow returning buffer with original lifetime)
 - #132803 (Fix broken url)
 - #132982 (alloc: fix `Allocator` method names in `alloc` free function docs)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Nov 25, 2024
2 parents 67a8c64 + d2590e0 commit 1278dad
Show file tree
Hide file tree
Showing 34 changed files with 1,655 additions and 198 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_ast_lowering/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ ast_lowering_register2 = register `{$reg2_name}`
ast_lowering_register_class_only_clobber =
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
ast_lowering_register_class_only_clobber_stable =
register class `{$reg_class_name}` can only be used as a clobber in stable
ast_lowering_register_conflict =
register `{$reg1_name}` conflicts with register `{$reg2_name}`
Expand Down Expand Up @@ -181,6 +183,8 @@ ast_lowering_underscore_expr_lhs_assign =
.label = `_` not allowed here
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
using both label and output operands for inline assembly is unstable
ast_lowering_unstable_inline_assembly_label_operands =
label operands for inline assembly are unstable
ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
Expand Down
76 changes: 61 additions & 15 deletions compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use super::errors::{
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable,
RegisterConflict,
};
use crate::{
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
Expand Down Expand Up @@ -61,6 +62,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
.emit();
}
}
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
&& !self.tcx.sess.opts.actually_rustdoc
Expand Down Expand Up @@ -239,15 +241,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
InlineAsmOperand::Label { block } => {
if !self.tcx.features().asm_goto() {
feature_err(
sess,
sym::asm_goto,
*op_sp,
fluent::ast_lowering_unstable_inline_assembly_label_operands,
)
.emit();
}
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
}
};
Expand Down Expand Up @@ -333,11 +326,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// means that we disallow passing a value in/out of the asm and
// require that the operand name an explicit register, not a
// register class.
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
self.dcx().emit_err(RegisterClassOnlyClobber {
op_span: op_sp,
reg_class_name: reg_class.name(),
});
if reg_class.is_clobber_only(asm_arch.unwrap(), allow_experimental_reg)
&& !op.is_clobber()
{
if allow_experimental_reg || reg_class.is_clobber_only(asm_arch.unwrap(), true)
{
// always clobber-only
self.dcx().emit_err(RegisterClassOnlyClobber {
op_span: op_sp,
reg_class_name: reg_class.name(),
});
} else {
// clobber-only in stable
self.tcx
.sess
.create_feature_err(
RegisterClassOnlyClobberStable {
op_span: op_sp,
reg_class_name: reg_class.name(),
},
sym::asm_experimental_reg,
)
.emit();
}
continue;
}

Expand Down Expand Up @@ -466,6 +477,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}

// Feature gate checking for asm goto.
if let Some((_, op_sp)) =
operands.iter().find(|(op, _)| matches!(op, hir::InlineAsmOperand::Label { .. }))
{
if !self.tcx.features().asm_goto() {
feature_err(
sess,
sym::asm_goto,
*op_sp,
fluent::ast_lowering_unstable_inline_assembly_label_operands,
)
.emit();
}

// In addition, check if an output operand is used.
// This is gated behind an additional feature.
let output_operand_used = operands.iter().any(|(op, _)| {
matches!(
op,
hir::InlineAsmOperand::Out { expr: Some(_), .. }
| hir::InlineAsmOperand::InOut { .. }
| hir::InlineAsmOperand::SplitInOut { out_expr: Some(_), .. }
)
});
if output_operand_used && !self.tcx.features().asm_goto_with_outputs() {
feature_err(
sess,
sym::asm_goto_with_outputs,
*op_sp,
fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs,
)
.emit();
}
}

let operands = self.arena.alloc_from_iter(operands);
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
let template_strs = self.arena.alloc_from_iter(
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast_lowering/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,14 @@ pub(crate) struct RegisterClassOnlyClobber {
pub reg_class_name: Symbol,
}

#[derive(Diagnostic)]
#[diag(ast_lowering_register_class_only_clobber_stable)]
pub(crate) struct RegisterClassOnlyClobberStable {
#[primary_span]
pub op_span: Span,
pub reg_class_name: Symbol,
}

#[derive(Diagnostic)]
#[diag(ast_lowering_register_conflict)]
pub(crate) struct RegisterConflict<'a> {
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,10 @@ pub fn parse_asm_args<'a>(
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
}
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
if args.options.contains(ast::InlineAsmOptions::NORETURN)
&& !outputs_sp.is_empty()
&& labels_sp.is_empty()
{
let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
// Bail out now since this is likely to confuse MIR
return Err(err);
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_codegen_cranelift/src/inline_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
let mut slots_output = vec![None; self.operands.len()];

let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| {
let reg_size =
reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap();
let reg_size = reg_class
.supported_types(self.arch, true)
.iter()
.map(|(ty, _)| ty.size())
.max()
.unwrap();
let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap();
let offset = slot_size.align_to(align);
*slot_size = offset + reg_size;
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_codegen_gcc/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
// `clobber_abi` can add lots of clobbers that are not supported by the target,
// such as AVX-512 registers, so we just ignore unsupported registers
let is_target_supported =
reg.reg_class().supported_types(asm_arch).iter().any(
reg.reg_class().supported_types(asm_arch, true).iter().any(
|&(_, feature)| {
if let Some(feature) = feature {
self.tcx
Expand Down Expand Up @@ -683,9 +683,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::S390x(
S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg,
) => {
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
Expand Down Expand Up @@ -766,7 +765,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
) => cx.type_i32(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
Expand Down
52 changes: 31 additions & 21 deletions compiler/rustc_codegen_llvm/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
match *op {
InlineAsmOperandRef::Out { reg, late, place } => {
let is_target_supported = |reg_class: InlineAsmRegClass| {
for &(_, feature) in reg_class.supported_types(asm_arch) {
for &(_, feature) in reg_class.supported_types(asm_arch, true) {
if let Some(feature) = feature {
if self
.tcx
Expand Down Expand Up @@ -85,7 +85,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
continue;
} else if !is_target_supported(reg.reg_class())
|| reg.reg_class().is_clobber_only(asm_arch)
|| reg.reg_class().is_clobber_only(asm_arch, true)
{
// We turn discarded outputs into clobber constraints
// if the target feature needed by the register class is
Expand Down Expand Up @@ -342,24 +342,32 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });

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

// Write results to outputs
for (idx, op) in operands.iter().enumerate() {
if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
| InlineAsmOperandRef::InOut { reg, out_place: Some(place), .. } = *op
{
let value = if output_types.len() == 1 {
result
} else {
self.extract_value(result, op_idx[&idx] as u64)
};
let value =
llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
OperandValue::Immediate(value).store(self, place);
for (idx, op) in operands.iter().enumerate() {
if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
| InlineAsmOperandRef::InOut { reg, out_place: Some(place), .. } = *op
{
let value = if output_types.len() == 1 {
result
} else {
self.extract_value(result, op_idx[&idx] as u64)
};
let value =
llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
OperandValue::Immediate(value).store(self, place);
}
}
}
}
Expand Down Expand Up @@ -678,7 +686,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
S390x(S390xInlineAsmRegClass::reg) => "r",
S390x(S390xInlineAsmRegClass::reg_addr) => "a",
S390x(S390xInlineAsmRegClass::freg) => "f",
S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
S390x(S390xInlineAsmRegClass::vreg) => "v",
S390x(S390xInlineAsmRegClass::areg) => {
unreachable!("clobber-only")
}
Sparc(SparcInlineAsmRegClass::reg) => "r",
Expand Down Expand Up @@ -844,7 +853,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(),
S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
S390x(S390xInlineAsmRegClass::areg) => {
unreachable!("clobber-only")
}
Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,12 @@ declare_features! (
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
/// Enables experimental inline assembly support for additional architectures.
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
/// Enables experimental register support in inline assembly.
(unstable, asm_experimental_reg, "CURRENT_RUSTC_VERSION", Some(133416)),
/// Allows using `label` operands in inline assembly.
(unstable, asm_goto, "1.78.0", Some(119364)),
/// Allows using `label` operands in inline assembly together with output operands.
(unstable, asm_goto_with_outputs, "CURRENT_RUSTC_VERSION", Some(119364)),
/// Allows the `may_unwind` option in inline assembly.
(unstable, asm_unwind, "1.58.0", Some(93334)),
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,9 @@ hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
hir_analysis_register_type_unstable =
type `{$ty}` cannot be used with this register class in stable
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
hir_analysis_return_type_notation_equality_bound =
Expand Down
38 changes: 27 additions & 11 deletions compiler/rustc_hir_analysis/src/check/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ use rustc_hir::{self as hir, LangItem};
use rustc_middle::bug;
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
use rustc_session::lint;
use rustc_span::Symbol;
use rustc_span::def_id::LocalDefId;
use rustc_span::{Symbol, sym};
use rustc_target::asm::{
InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
};

use crate::errors::RegisterTypeUnstable;

pub struct InlineAsmCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
Expand Down Expand Up @@ -218,17 +220,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
// Check the type against the list of types supported by the selected
// register class.
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
let reg_class = reg.reg_class();
let supported_tys = reg_class.supported_types(asm_arch);
let supported_tys = reg_class.supported_types(asm_arch, allow_experimental_reg);
let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
let msg = format!("type `{ty}` cannot be used with this register class");
let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect();
err.note(format!(
"register class `{}` supports these types: {}",
reg_class.name(),
supported_tys.join(", "),
));
let mut err = if !allow_experimental_reg
&& reg_class.supported_types(asm_arch, true).iter().any(|&(t, _)| t == asm_ty)
{
self.tcx.sess.create_feature_err(
RegisterTypeUnstable { span: expr.span, ty },
sym::asm_experimental_reg,
)
} else {
let msg = format!("type `{ty}` cannot be used with this register class");
let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
let supported_tys: Vec<_> =
supported_tys.iter().map(|(t, _)| t.to_string()).collect();
err.note(format!(
"register class `{}` supports these types: {}",
reg_class.name(),
supported_tys.join(", "),
));
err
};
if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) {
err.help(format!("consider using the `{}` register class instead", suggest.name()));
}
Expand Down Expand Up @@ -313,6 +327,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
self.tcx.dcx().delayed_bug("target architecture does not support asm");
return;
};
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
// Validate register classes against currently enabled target
// features. We check that at least one type is available for
Expand Down Expand Up @@ -352,7 +367,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if let InlineAsmRegClass::Err = reg_class {
continue;
}
for &(_, feature) in reg_class.supported_types(asm_arch) {
for &(_, feature) in reg_class.supported_types(asm_arch, allow_experimental_reg)
{
match feature {
Some(feature) => {
if target_features.contains(&feature) {
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1708,3 +1708,11 @@ pub(crate) struct CmseEntryGeneric {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_register_type_unstable)]
pub(crate) struct RegisterTypeUnstable<'a> {
#[primary_span]
pub span: Span,
pub ty: Ty<'a>,
}
Loading

0 comments on commit 1278dad

Please sign in to comment.