diff options
| author | Jakub Beránek <berykubik@gmail.com> | 2025-07-04 11:07:48 +0200 |
|---|---|---|
| committer | Jakub Beránek <berykubik@gmail.com> | 2025-07-04 11:07:48 +0200 |
| commit | c33dd1b306db360f92c46f1cab79e68e6a845bf5 (patch) | |
| tree | 3fa8e6c5426eb1fa41b4ac3e6ebeaa322ab89688 /compiler/rustc_codegen_ssa/src | |
| parent | ac1a8b398b8c0f33e982ba736d31492d911c3050 (diff) | |
| parent | c96a69059ecc618b519da385a6ccd03155aa0237 (diff) | |
| download | rust-c33dd1b306db360f92c46f1cab79e68e6a845bf5.tar.gz rust-c33dd1b306db360f92c46f1cab79e68e6a845bf5.zip | |
Merge ref 'c96a69059ecc' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref: c96a69059ecc618b519da385a6ccd03155aa0237 Filtered ref: 7b9552d4c39c31aabf6749629da2d4a7e6e1cd60 This merge was created using https://github.com/rust-lang/josh-sync.
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/linker.rs | 30 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/metadata.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/symbol_export.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/write.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/base.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 255 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/errors.rs | 37 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/block.rs | 77 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/mod.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/operand.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/target_features.rs | 149 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/traits/builder.rs | 2 |
15 files changed, 264 insertions, 447 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4a2425967e4..343cb0eeca9 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2767,7 +2767,7 @@ fn add_upstream_rust_crates( if sess.target.is_like_aix { // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override - // the dependency name when outputing a shared library. Thus, `ld` will + // the dependency name when outputting a shared library. Thus, `ld` will // use the full path to shared libraries as the dependency if passed it // by default unless `noipath` is passed. // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command. @@ -3051,7 +3051,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // Supported architecture names can be found in the source: // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 // - // Intentially verbose to ensure that the list always matches correctly + // Intentionally verbose to ensure that the list always matches correctly // with the list in the source above. let ld64_arch = match llvm_arch { "armv7k" => "armv7k", @@ -3118,7 +3118,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // We do not currently know the actual SDK version though, so we have a few options: // 1. Use the minimum version supported by rustc. // 2. Use the same as the deployment target. - // 3. Use an arbitary recent version. + // 3. Use an arbitrary recent version. // 4. Omit the version. // // The first option is too low / too conservative, and means that users will not get the diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index cd08c0fc30f..1896f63bd2d 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1794,7 +1794,10 @@ fn for_each_exported_symbols_include_dep<'tcx>( for (cnum, dep_format) in deps.iter_enumerated() { // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { - for &(symbol, info) in tcx.exported_symbols(cnum).iter() { + for &(symbol, info) in tcx.exported_non_generic_symbols(cnum).iter() { + callback(symbol, info, cnum); + } + for &(symbol, info) in tcx.exported_generic_symbols(cnum).iter() { callback(symbol, info, cnum); } } @@ -1870,8 +1873,28 @@ pub(crate) fn linked_symbols( crate_type: CrateType, ) -> Vec<(String, SymbolExportKind)> { match crate_type { - CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (), - CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { + CrateType::Executable + | CrateType::ProcMacro + | CrateType::Cdylib + | CrateType::Dylib + | CrateType::Sdylib => (), + CrateType::Staticlib | CrateType::Rlib => { + // These are not linked, so no need to generate symbols.o for them. + return Vec::new(); + } + } + + match tcx.sess.lto() { + Lto::No | Lto::ThinLocal => {} + Lto::Thin | Lto::Fat => { + // We really only need symbols from upstream rlibs to end up in the linked symbols list. + // The rest are in separate object files which the linker will always link in and + // doesn't have rules around the order in which they need to appear. + // When doing LTO, some of the symbols in the linked symbols list happen to be + // internalized by LTO, which then prevents referencing them from symbols.o. When doing + // LTO, all object files that get linked in will be local object files rather than + // pulled in from rlibs, so an empty linked symbols list works fine to avoid referencing + // all those internalized symbols from symbols.o. return Vec::new(); } } @@ -1882,6 +1905,7 @@ pub(crate) fn linked_symbols( for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) || info.used + || info.rustc_std_internal_symbol { symbols.push(( symbol_export::linking_symbol_name_for_instance_in_crate( diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d091c46d9c1..bf38c02e908 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -301,7 +301,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, "n64" if !is_32bit => {} "" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, - "" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"), + "" => sess.dcx().fatal("LLVM ABI must be specified for 64-bit MIPS targets"), s if is_32bit => { sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s)) } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 19c005d418e..2f5eca2d6b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -131,6 +131,9 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || used, + rustc_std_internal_symbol: codegen_attrs + .flags + .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL), }; (def_id.to_def_id(), info) }) @@ -143,6 +146,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + rustc_std_internal_symbol: false, }, ); } @@ -164,7 +168,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) } -fn exported_symbols_provider_local<'tcx>( +fn exported_non_generic_symbols_provider_local<'tcx>( tcx: TyCtxt<'tcx>, _: LocalCrate, ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { @@ -191,6 +195,7 @@ fn exported_symbols_provider_local<'tcx>( level: info.level, kind: SymbolExportKind::Text, used: info.used, + rustc_std_internal_symbol: info.rustc_std_internal_symbol, }, ) }) @@ -207,6 +212,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -230,6 +236,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: true, }, )); } @@ -250,6 +257,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + rustc_std_internal_symbol: false, }, ) })); @@ -275,6 +283,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + rustc_std_internal_symbol: false, }, ) })); @@ -292,10 +301,27 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: true, + rustc_std_internal_symbol: false, }, )); } + // Sort so we get a stable incr. comp. hash. + symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); + + tcx.arena.alloc_from_iter(symbols) +} + +fn exported_generic_symbols_provider_local<'tcx>( + tcx: TyCtxt<'tcx>, + _: LocalCrate, +) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { + if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() { + return &[]; + } + + let mut symbols: Vec<_> = vec![]; + if tcx.local_crate_exports_generics() { use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; use rustc_middle::ty::InstanceKind; @@ -367,6 +393,8 @@ fn exported_symbols_provider_local<'tcx>( } } + // Note: These all set rustc_std_internal_symbol to false as generic functions must not + // be marked with this attribute and we are only handling generic functions here. match *mono_item { MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { let has_generics = args.non_erasable_generics().next().is_some(); @@ -382,6 +410,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -404,6 +433,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -420,6 +450,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -430,6 +461,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -458,7 +490,7 @@ fn upstream_monomorphizations_provider( let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn(); for &cnum in cnums.iter() { - for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { + for (exported_symbol, _) in tcx.exported_generic_symbols(cnum).iter() { let (def_id, args) = match *exported_symbol { ExportedSymbol::Generic(def_id, args) => (def_id, args), ExportedSymbol::DropGlue(ty) => { @@ -480,10 +512,7 @@ fn upstream_monomorphizations_provider( ExportedSymbol::AsyncDropGlue(def_id, ty) => (def_id, tcx.mk_args(&[ty.into()])), ExportedSymbol::NonGeneric(..) | ExportedSymbol::ThreadLocalShim(..) - | ExportedSymbol::NoDefId(..) => { - // These are no monomorphizations - continue; - } + | ExportedSymbol::NoDefId(..) => unreachable!("{exported_symbol:?}"), }; let args_map = instances.entry(def_id).or_default(); @@ -538,7 +567,8 @@ fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) pub(crate) fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; - providers.exported_symbols = exported_symbols_provider_local; + providers.exported_non_generic_symbols = exported_non_generic_symbols_provider_local; + providers.exported_generic_symbols = exported_generic_symbols_provider_local; providers.upstream_monomorphizations = upstream_monomorphizations_provider; providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c3bfe4c13cd..8330e4f7af0 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1124,8 +1124,9 @@ fn start_executing_work<B: ExtraBackendMethods>( let copy_symbols = |cnum| { let symbols = tcx - .exported_symbols(cnum) + .exported_non_generic_symbols(cnum) .iter() + .chain(tcx.exported_generic_symbols(cnum)) .map(|&(s, lvl)| (symbol_name_for_instance_in_crate(tcx, s, cnum), lvl)) .collect(); Arc::new(symbols) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index cc90271cd0c..102d4ea2fa6 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -6,7 +6,7 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast as ast; -use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr_data_structures::OptimizeAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; @@ -262,28 +262,6 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type. -pub(crate) fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - src: Bx::Value, - src_ty_and_layout: TyAndLayout<'tcx>, - dst_ty: Ty<'tcx>, - old_info: Option<Bx::Value>, -) -> (Bx::Value, Bx::Value) { - debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty); - assert!( - matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)), - "destination type must be a dyn*" - ); - let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) { - TypeKind::Pointer => src, - TypeKind::Integer => bx.inttoptr(src, bx.type_ptr()), - // FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr. - kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"), - }; - (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info)) -} - /// Coerces `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty`, and stores the result in `dst`. pub(crate) fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( @@ -1056,26 +1034,6 @@ impl CrateInfo { .collect::<Vec<_>>(); symbols.sort_unstable_by(|a, b| a.0.cmp(&b.0)); linked_symbols.extend(symbols); - if tcx.allocator_kind(()).is_some() { - // At least one crate needs a global allocator. This crate may be placed - // after the crate that defines it in the linker order, in which case some - // linkers return an error. By adding the global allocator shim methods to - // the linked_symbols list, linking the generated symbols.o will ensure that - // circular dependencies involving the global allocator don't lead to linker - // errors. - linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| { - ( - add_prefix( - mangle_internal_symbol( - tcx, - global_fn_name(method.name).as_str(), - ), - SymbolExportKind::Text, - ), - SymbolExportKind::Text, - ) - })); - } }); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 7bd27eb3ef1..2713ec07f97 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,15 +1,15 @@ use std::str::FromStr; -use rustc_abi::ExternAbi; +use rustc_abi::{Align, ExternAbi}; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; use rustc_attr_data_structures::{ - AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, find_attr, + AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, UsedBy, find_attr, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{self as hir, HirId, LangItem, lang_items}; +use rustc_hir::{self as hir, LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -87,7 +87,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut link_ordinal_span = None; let mut no_sanitize_span = None; - let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -119,16 +118,18 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .max(); } AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, + AttributeKind::ExportName { name, .. } => { + codegen_fn_attrs.export_name = Some(*name); + } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), + AttributeKind::LinkSection { name, .. } => { + codegen_fn_attrs.link_section = Some(*name) + } AttributeKind::NoMangle(attr_span) => { if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - mixed_export_name_no_mangle_lint_state.track_no_mangle( - *attr_span, - tcx.local_def_id_to_hir_id(did), - attr, - ); } else { tcx.dcx().emit_err(NoMangleNameless { span: *attr_span, @@ -140,6 +141,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }); } } + AttributeKind::TargetFeature(features, attr_span) => { + let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { + tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn"); + continue; + }; + let safe_target_features = + matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures); + codegen_fn_attrs.safe_target_features = safe_target_features; + if safe_target_features { + if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { + // The `#[target_feature]` attribute is allowed on + // WebAssembly targets on all functions. Prior to stabilizing + // the `target_feature_11` feature, `#[target_feature]` was + // only permitted on unsafe functions because on most targets + // execution of instructions that are not supported is + // considered undefined behavior. For WebAssembly which is a + // 100% safe target at execution time it's not possible to + // execute undefined instructions, and even if a future + // feature was added in some form for this it would be a + // deterministic trap. There is no undefined behavior when + // executing WebAssembly so `#[target_feature]` is allowed + // on safe functions (but again, only for WebAssembly) + // + // Note that this is also allowed if `actually_rustdoc` so + // if a target is documenting some wasm-specific code then + // it's not spuriously denied. + // + // Now that `#[target_feature]` is permitted on safe functions, + // this exception must still exist for allowing the attribute on + // `main`, `start`, and other functions that are not usually + // allowed. + } else { + check_target_feature_trait_unsafe(tcx, did, *attr_span); + } + } + from_target_feature_attr( + tcx, + did, + features, + rust_target_features, + &mut codegen_fn_attrs.target_features, + ); + } AttributeKind::TrackCaller(attr_span) => { let is_closure = tcx.is_closure_like(did.to_def_id()); @@ -163,6 +207,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER } + AttributeKind::Used { used_by, .. } => match used_by { + UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER, + UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER, + }, _ => {} } } @@ -184,99 +232,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::rustc_std_internal_symbol => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } - sym::used => { - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if !tcx.features().used_with_arg() { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span(), - "`#[used(linker)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; - } - Some([item]) if item.has_name(sym::compiler) => { - if !tcx.features().used_with_arg() { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span(), - "`#[used(compiler)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER; - } - Some(_) => { - tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() }); - } - None => { - // Unconditionally using `llvm.used` causes issues in handling - // `.init_array` with the gold linker. Luckily gold has been - // deprecated with GCC 15 and rustc now warns about using gold. - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER - } - } - } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, - sym::export_name => { - if let Some(s) = attr.value_str() { - if s.as_str().contains('\0') { - // `#[export_name = ...]` will be converted to a null-terminated string, - // so it may not contain any null characters. - tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() }); - } - codegen_fn_attrs.export_name = Some(s); - mixed_export_name_no_mangle_lint_state.track_export_name(attr.span()); - } - } - sym::target_feature => { - let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { - tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn"); - continue; - }; - let safe_target_features = - matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures); - codegen_fn_attrs.safe_target_features = safe_target_features; - if safe_target_features { - if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { - // The `#[target_feature]` attribute is allowed on - // WebAssembly targets on all functions. Prior to stabilizing - // the `target_feature_11` feature, `#[target_feature]` was - // only permitted on unsafe functions because on most targets - // execution of instructions that are not supported is - // considered undefined behavior. For WebAssembly which is a - // 100% safe target at execution time it's not possible to - // execute undefined instructions, and even if a future - // feature was added in some form for this it would be a - // deterministic trap. There is no undefined behavior when - // executing WebAssembly so `#[target_feature]` is allowed - // on safe functions (but again, only for WebAssembly) - // - // Note that this is also allowed if `actually_rustdoc` so - // if a target is documenting some wasm-specific code then - // it's not spuriously denied. - // - // Now that `#[target_feature]` is permitted on safe functions, - // this exception must still exist for allowing the attribute on - // `main`, `start`, and other functions that are not usually - // allowed. - } else { - check_target_feature_trait_unsafe(tcx, did, attr.span()); - } - } - from_target_feature_attr( - tcx, - did, - attr, - rust_target_features, - &mut codegen_fn_attrs.target_features, - ); - } sym::linkage => { if let Some(val) = attr.value_str() { let linkage = Some(linkage_by_name(tcx, did, val.as_str())); @@ -300,17 +256,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } } - sym::link_section => { - if let Some(val) = attr.value_str() { - if val.as_str().bytes().any(|b| b == 0) { - let msg = format!("illegal null byte in link_section value: `{val}`"); - tcx.dcx().span_err(attr.span(), msg); - } else { - codegen_fn_attrs.link_section = Some(val); - } - } - } - sym::link_name => codegen_fn_attrs.link_name = attr.value_str(), sym::link_ordinal => { link_ordinal_span = Some(attr.span()); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { @@ -444,12 +389,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - - // Apply the minimum function alignment here, so that individual backends don't have to. + // Apply the minimum function alignment here. This ensures that a function's alignment is + // determined by the `-C` flags of the crate it is defined in, not the `-C` flags of the crate + // it happens to be codegen'd (or const-eval'd) in. codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment); + // On trait methods, inherit the `#[align]` of the trait's method prototype. + codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did)); + let inline_span; (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) @@ -588,10 +536,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .map(|features| (features.name.as_str(), true)) .collect(), ) { - let span = tcx - .get_attrs(did, sym::target_feature) - .next() - .map_or_else(|| tcx.def_span(did), |a| a.span()); + let span = + find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span) + .unwrap_or_else(|| tcx.def_span(did)); + tcx.dcx() .create_err(errors::TargetFeatureDisableOrEnable { features, @@ -604,17 +552,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs } +/// If the provided DefId is a method in a trait impl, return the DefId of the method prototype. +fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { + let impl_item = tcx.opt_associated_item(def_id)?; + match impl_item.container { + ty::AssocItemContainer::Impl => impl_item.trait_item_def_id, + _ => None, + } +} + /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if let Some(impl_item) = tcx.opt_associated_item(def_id) - && let ty::AssocItemContainer::Impl = impl_item.container - && let Some(trait_item) = impl_item.trait_item_def_id - { - return tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER); - } + let Some(trait_item) = opt_trait_item(tcx, def_id) else { return false }; + tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER) +} - false +/// If the provided DefId is a method in a trait impl, return the value of the `#[align]` +/// attribute on the method prototype (if any). +fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> { + tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment } fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> { @@ -672,49 +629,6 @@ fn check_link_name_xor_ordinal( } } -#[derive(Default)] -struct MixedExportNameAndNoMangleState<'a> { - export_name: Option<Span>, - hir_id: Option<HirId>, - no_mangle: Option<Span>, - no_mangle_attr: Option<&'a hir::Attribute>, -} - -impl<'a> MixedExportNameAndNoMangleState<'a> { - fn track_export_name(&mut self, span: Span) { - self.export_name = Some(span); - } - - fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) { - self.no_mangle = Some(span); - self.hir_id = Some(hir_id); - self.no_mangle_attr = Some(attr_name); - } - - /// Emit diagnostics if the lint condition is met. - fn lint_if_mixed(self, tcx: TyCtxt<'_>) { - if let Self { - export_name: Some(export_name), - no_mangle: Some(no_mangle), - hir_id: Some(hir_id), - no_mangle_attr: Some(_), - } = self - { - tcx.emit_node_span_lint( - lint::builtin::UNUSED_ATTRIBUTES, - hir_id, - no_mangle, - errors::MixedExportNameAndNoMangle { - no_mangle, - no_mangle_attr: "#[unsafe(no_mangle)]".to_string(), - export_name, - removal_span: no_mangle, - }, - ); - } - } -} - /// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)] /// macros. There are two forms. The pure one without args to mark primal functions (the functions /// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the @@ -825,5 +739,6 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; + *providers = + Providers { codegen_fn_attrs, should_inherit_track_caller, inherited_align, ..*providers }; } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index caac0f83f9d..086c069745c 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -141,13 +141,6 @@ pub(crate) struct RequiresRustAbi { } #[derive(Diagnostic)] -#[diag(codegen_ssa_null_on_export, code = E0648)] -pub(crate) struct NullOnExport { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(codegen_ssa_unsupported_instruction_set, code = E0779)] pub(crate) struct UnsupportedInstructionSet { #[primary_span] @@ -734,13 +727,6 @@ pub struct UnknownArchiveKind<'a> { } #[derive(Diagnostic)] -#[diag(codegen_ssa_expected_used_symbol)] -pub(crate) struct ExpectedUsedSymbol { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(codegen_ssa_multiple_main_functions)] #[help] pub(crate) struct MultipleMainFunctions { @@ -1207,18 +1193,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> { #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; -#[derive(LintDiagnostic)] -#[diag(codegen_ssa_mixed_export_name_and_no_mangle)] -pub(crate) struct MixedExportNameAndNoMangle { - #[label] - pub no_mangle: Span, - pub no_mangle_attr: String, - #[note] - pub export_name: Span, - #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] - pub removal_span: Span, -} - #[derive(Diagnostic, Debug)] pub(crate) enum XcrunError { #[diag(codegen_ssa_xcrun_failed_invoking)] @@ -1318,3 +1292,14 @@ pub(crate) struct NoMangleNameless { pub span: Span, pub definition: String, } + +#[derive(Diagnostic)] +#[diag(codegen_ssa_feature_not_valid)] +pub(crate) struct FeatureNotValid<'a> { + pub feature: &'a str, + #[primary_span] + #[label] + pub span: Span, + #[help] + pub plus_hint: bool, +} diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 3df97429e09..bde63fd501a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -628,50 +628,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { virtual_drop, ) } - ty::Dynamic(_, _, ty::DynStar) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn* Trait) - // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>) - // - // args = [ * ] - // | - // v - // ( Data, Vtable ) - // | - // v - // /-------\ - // | ... | - // \-------/ - // - // - // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING - // - // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) - // vtable = (*args[0]).1 // loads the vtable out - // (data, vtable) // an equivalent Rust `*mut dyn Trait` - // - // SO THEN WE CAN USE THE ABOVE CODE. - let virtual_drop = Instance { - def: ty::InstanceKind::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function - args: drop_fn.args, - }; - debug!("ty = {:?}", ty); - debug!("drop_fn = {:?}", drop_fn); - debug!("args = {:?}", args); - let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); - let meta_ptr = place.project_field(bx, 1); - let meta = bx.load_operand(meta_ptr); - // Truncate vtable off of args list - args = &args[..1]; - debug!("args' = {:?}", args); - ( - true, - meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) - .get_optional_fn(bx, meta.immediate(), ty, fn_abi), - fn_abi, - virtual_drop, - ) - } _ => ( false, bx.get_fn_addr(drop_fn), @@ -776,6 +732,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // `#[track_caller]` adds an implicit argument. (LangItem::PanicNullPointerDereference, vec![location]) } + AssertKind::InvalidEnumConstruction(source) => { + let source = self.codegen_operand(bx, source).immediate(); + // It's `fn panic_invalid_enum_construction(source: u128)`, + // `#[track_caller]` adds an implicit argument. + (LangItem::PanicInvalidEnumConstruction, vec![source, location]) + } _ => { // It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument. (msg.panic_function(), vec![location]) @@ -1102,33 +1064,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llargs.push(data_ptr); continue; } - Immediate(_) => { - // See comment above explaining why we peel these newtypes - while !op.layout.ty.is_raw_ptr() && !op.layout.ty.is_ref() { - let (idx, _) = op.layout.non_1zst_field(bx).expect( - "not exactly one non-1-ZST field in a `DispatchFromDyn` type", - ); - op = op.extract_field(self, bx, idx.as_usize()); - } - - // Make sure that we've actually unwrapped the rcvr down - // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { - span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); - } - let place = op.deref(bx.cx()); - let data_place = place.project_field(bx, 0); - let meta_place = place.project_field(bx, 1); - let meta = bx.load_operand(meta_place); - llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( - bx, - meta.immediate(), - op.layout.ty, - fn_abi, - )); - llargs.push(data_place.val.llval); - continue; - } _ => { span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 27fcab8ed2d..fc95f62b4a4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,7 +1,7 @@ use rustc_abi::WrappingRange; -use rustc_middle::bug; use rustc_middle::mir::SourceInfo; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::sym; @@ -98,6 +98,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { discr.to_atomic_ordering() }; + if args.is_empty() { + match name { + sym::abort + | sym::unreachable + | sym::cold_path + | sym::breakpoint + | sym::assert_zero_valid + | sym::assert_mem_uninitialized_valid + | sym::assert_inhabited + | sym::ub_checks + | sym::contract_checks + | sym::atomic_fence + | sym::atomic_singlethreadfence + | sym::caller_location => {} + _ => { + span_bug!(span, "nullary intrinsic {name} must either be in a const block or explicitly opted out because it is inherently a runtime intrinsic +"); + } + } + } + let llval = match name { sym::abort => { bx.abort(); @@ -150,10 +171,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } value } - sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { - let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap(); - OperandRef::from_const(bx, value, result.layout.ty).immediate_or_packed_pair(bx) - } sym::arith_offset => { let ty = fn_args.type_at(0); let layout = bx.layout_of(ty); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 66c4af4c935..10b44a1faf0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -354,15 +354,15 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let destination_block = target.unwrap(); - bb.statements.push(mir::Statement { - source_info: bb.terminator().source_info, - kind: mir::StatementKind::Assign(Box::new(( + bb.statements.push(mir::Statement::new( + bb.terminator().source_info, + mir::StatementKind::Assign(Box::new(( *destination, mir::Rvalue::Use(mir::Operand::Copy( arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx), )), ))), - }); + )); bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block }; } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 99957c67708..da615cc9a00 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -479,17 +479,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), }; - // Layout ensures that we only get here for cases where the discriminant + // `layout_sanity_check` ensures that we only get here for cases where the discriminant // value and the variant index match, since that's all `Niche` can encode. - // But for emphasis and debugging, let's double-check one anyway. - debug_assert_eq!( - self.layout - .ty - .discriminant_for_variant(bx.tcx(), untagged_variant) - .unwrap() - .val, - u128::from(untagged_variant.as_u32()), - ); let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index db5ac6a514f..60cf4e28b5a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -468,12 +468,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("unexpected non-pair operand"); } } - mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { - let (lldata, llextra) = operand.val.pointer_parts(); - let (lldata, llextra) = - base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra); - OperandValue::Pair(lldata, llextra) - } | mir::CastKind::IntToInt | mir::CastKind::FloatToInt | mir::CastKind::FloatToFloat @@ -1123,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // While optimizations will remove no-op transmutes, they might still be // there in debug or things that aren't no-op in MIR because they change // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar { + if from_scalar == to_scalar && from_backend_ty == to_backend_ty { return imm; } @@ -1142,13 +1136,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | Float(_), Int(..) | Float(_)) => { - if from_backend_ty == to_backend_ty { - imm - } else { - bx.bitcast(imm, to_backend_ty) - } - } + (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), (Pointer(..), Int(..)) => { diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 67ac619091b..53df99993f0 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,8 +1,6 @@ use rustc_attr_data_structures::InstructionSetAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; @@ -12,110 +10,85 @@ use rustc_session::Session; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability}; +use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; -use crate::errors; +use crate::errors::FeatureNotValid; +use crate::{errors, target_features}; /// Compute the enabled target features from the `#[target_feature]` function attribute. /// Enabled target features are added to `target_features`. pub(crate) fn from_target_feature_attr( tcx: TyCtxt<'_>, did: LocalDefId, - attr: &hir::Attribute, + features: &[(Symbol, Span)], rust_target_features: &UnordMap<String, target_features::Stability>, target_features: &mut Vec<TargetFeature>, ) { - let Some(list) = attr.meta_item_list() else { return }; - let bad_item = |span| { - let msg = "malformed `target_feature` attribute input"; - let code = "enable = \"..\""; - tcx.dcx() - .struct_span_err(span, msg) - .with_span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) - .emit(); - }; let rust_features = tcx.features(); let abi_feature_constraints = tcx.sess.target.abi_required_features(); - for item in list { - // Only `enable = ...` is accepted in the meta-item list. - if !item.has_name(sym::enable) { - bad_item(item.span()); - continue; - } - - // Must be of the form `enable = "..."` (a string). - let Some(value) = item.value_str() else { - bad_item(item.span()); + for &(feature, feature_span) in features { + let feature_str = feature.as_str(); + let Some(stability) = rust_target_features.get(feature_str) else { + let plus_hint = feature_str + .strip_prefix('+') + .is_some_and(|stripped| rust_target_features.contains_key(stripped)); + tcx.dcx().emit_err(FeatureNotValid { + feature: feature_str, + span: feature_span, + plus_hint, + }); continue; }; - // We allow comma separation to enable multiple features. - for feature in value.as_str().split(',') { - let Some(stability) = rust_target_features.get(feature) else { - let msg = format!("the feature named `{feature}` is not valid for this target"); - let mut err = tcx.dcx().struct_span_err(item.span(), msg); - err.span_label(item.span(), format!("`{feature}` is not valid for this target")); - if let Some(stripped) = feature.strip_prefix('+') { - let valid = rust_target_features.contains_key(stripped); - if valid { - err.help("consider removing the leading `+` in the feature name"); - } - } - err.emit(); - continue; - }; - - // Only allow target features whose feature gates have been enabled - // and which are permitted to be toggled. - if let Err(reason) = stability.toggle_allowed() { - tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { - span: item.span(), - feature, - reason, - }); - } else if let Some(nightly_feature) = stability.requires_nightly() - && !rust_features.enabled(nightly_feature) - { - feature_err( - &tcx.sess, - nightly_feature, - item.span(), - format!("the target feature `{feature}` is currently unstable"), - ) - .emit(); - } else { - // Add this and the implied features. - let feature_sym = Symbol::intern(feature); - for &name in tcx.implied_target_features(feature_sym) { - // But ensure the ABI does not forbid enabling this. - // Here we do assume that the backend doesn't add even more implied features - // we don't know about, at least no features that would have ABI effects! - // We skip this logic in rustdoc, where we want to allow all target features of - // all targets, so we can't check their ABI compatibility and anyway we are not - // generating code so "it's fine". - if !tcx.sess.opts.actually_rustdoc { - if abi_feature_constraints.incompatible.contains(&name.as_str()) { - // For "neon" specifically, we emit an FCW instead of a hard error. - // See <https://github.com/rust-lang/rust/issues/134375>. - if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" { - tcx.emit_node_span_lint( - AARCH64_SOFTFLOAT_NEON, - tcx.local_def_id_to_hir_id(did), - item.span(), - errors::Aarch64SoftfloatNeon, - ); - } else { - tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { - span: item.span(), - feature: name.as_str(), - reason: "this feature is incompatible with the target ABI", - }); - } + // Only allow target features whose feature gates have been enabled + // and which are permitted to be toggled. + if let Err(reason) = stability.toggle_allowed() { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: feature_span, + feature: feature_str, + reason, + }); + } else if let Some(nightly_feature) = stability.requires_nightly() + && !rust_features.enabled(nightly_feature) + { + feature_err( + &tcx.sess, + nightly_feature, + feature_span, + format!("the target feature `{feature}` is currently unstable"), + ) + .emit(); + } else { + // Add this and the implied features. + for &name in tcx.implied_target_features(feature) { + // But ensure the ABI does not forbid enabling this. + // Here we do assume that the backend doesn't add even more implied features + // we don't know about, at least no features that would have ABI effects! + // We skip this logic in rustdoc, where we want to allow all target features of + // all targets, so we can't check their ABI compatibility and anyway we are not + // generating code so "it's fine". + if !tcx.sess.opts.actually_rustdoc { + if abi_feature_constraints.incompatible.contains(&name.as_str()) { + // For "neon" specifically, we emit an FCW instead of a hard error. + // See <https://github.com/rust-lang/rust/issues/134375>. + if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" { + tcx.emit_node_span_lint( + AARCH64_SOFTFLOAT_NEON, + tcx.local_def_id_to_hir_id(did), + feature_span, + errors::Aarch64SoftfloatNeon, + ); + } else { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: feature_span, + feature: name.as_str(), + reason: "this feature is incompatible with the target ABI", + }); } } - target_features.push(TargetFeature { name, implied: name != feature_sym }) } + target_features.push(TargetFeature { name, implied: name != feature }) } } } @@ -457,7 +430,7 @@ pub(crate) fn provide(providers: &mut Providers) { // one, just keep it. } _ => { - // Overwrite stabilite. + // Overwrite stability. occupied_entry.insert(stability); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index d19de6f5d26..9d367748c2a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -87,7 +87,7 @@ pub trait BuilderMethods<'a, 'tcx>: // // This function is opt-in for back ends. // - // The default implementation calls `self.expect()` before emiting the branch + // The default implementation calls `self.expect()` before emitting the branch // by calling `self.cond_br()` fn cond_br_with_expect( &mut self, |
