Skip to content

Commit a8a4510

Browse files
Move some codegen-y methods from rustc_hir_analysis::collect -> rustc_codegen_ssa
1 parent b96d9e0 commit a8a4510

File tree

8 files changed

+857
-828
lines changed

8 files changed

+857
-828
lines changed

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+688
Large diffs are not rendered by default.

compiler/rustc_codegen_ssa/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,10 @@ pub struct ArchiveBuildFailure {
548548
pub struct UnknownArchiveKind<'a> {
549549
pub kind: &'a str,
550550
}
551+
552+
#[derive(Diagnostic)]
553+
#[diag(codegen_ssa_expected_used_symbol)]
554+
pub struct ExpectedUsedSymbol {
555+
#[primary_span]
556+
pub span: Span,
557+
}

compiler/rustc_codegen_ssa/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use std::path::{Path, PathBuf};
4242

4343
pub mod back;
4444
pub mod base;
45+
pub mod codegen_attrs;
4546
pub mod common;
4647
pub mod coverageinfo;
4748
pub mod debuginfo;
@@ -180,6 +181,7 @@ pub fn provide(providers: &mut Providers) {
180181
crate::back::symbol_export::provide(providers);
181182
crate::base::provide(providers);
182183
crate::target_features::provide(providers);
184+
crate::codegen_attrs::provide(providers);
183185
}
184186

185187
pub fn provide_extern(providers: &mut ExternProviders) {

compiler/rustc_codegen_ssa/src/target_features.rs

+154-10
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1+
use rustc_ast::ast;
2+
use rustc_attr::InstructionSetAttr;
3+
use rustc_data_structures::fx::FxHashMap;
4+
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_errors::Applicability;
6+
use rustc_hir as hir;
7+
use rustc_hir::def_id::DefId;
8+
use rustc_hir::def_id::LocalDefId;
19
use rustc_hir::def_id::LOCAL_CRATE;
210
use rustc_middle::ty::query::Providers;
11+
use rustc_middle::ty::TyCtxt;
12+
use rustc_session::parse::feature_err;
313
use rustc_session::Session;
414
use rustc_span::symbol::sym;
515
use rustc_span::symbol::Symbol;
16+
use rustc_span::Span;
617

718
/// Features that control behaviour of rustc, rather than the codegen.
819
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
@@ -322,15 +333,148 @@ pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]
322333
}
323334
}
324335

325-
pub(crate) fn provide(providers: &mut Providers) {
326-
providers.supported_target_features = |tcx, cnum| {
327-
assert_eq!(cnum, LOCAL_CRATE);
328-
if tcx.sess.opts.actually_rustdoc {
329-
// rustdoc needs to be able to document functions that use all the features, so
330-
// whitelist them all
331-
all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
332-
} else {
333-
supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
334-
}
336+
pub fn from_target_feature(
337+
tcx: TyCtxt<'_>,
338+
attr: &ast::Attribute,
339+
supported_target_features: &FxHashMap<String, Option<Symbol>>,
340+
target_features: &mut Vec<Symbol>,
341+
) {
342+
let Some(list) = attr.meta_item_list() else { return };
343+
let bad_item = |span| {
344+
let msg = "malformed `target_feature` attribute input";
345+
let code = "enable = \"..\"";
346+
tcx.sess
347+
.struct_span_err(span, msg)
348+
.span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
349+
.emit();
335350
};
351+
let rust_features = tcx.features();
352+
for item in list {
353+
// Only `enable = ...` is accepted in the meta-item list.
354+
if !item.has_name(sym::enable) {
355+
bad_item(item.span());
356+
continue;
357+
}
358+
359+
// Must be of the form `enable = "..."` (a string).
360+
let Some(value) = item.value_str() else {
361+
bad_item(item.span());
362+
continue;
363+
};
364+
365+
// We allow comma separation to enable multiple features.
366+
target_features.extend(value.as_str().split(',').filter_map(|feature| {
367+
let Some(feature_gate) = supported_target_features.get(feature) else {
368+
let msg =
369+
format!("the feature named `{}` is not valid for this target", feature);
370+
let mut err = tcx.sess.struct_span_err(item.span(), &msg);
371+
err.span_label(
372+
item.span(),
373+
format!("`{}` is not valid for this target", feature),
374+
);
375+
if let Some(stripped) = feature.strip_prefix('+') {
376+
let valid = supported_target_features.contains_key(stripped);
377+
if valid {
378+
err.help("consider removing the leading `+` in the feature name");
379+
}
380+
}
381+
err.emit();
382+
return None;
383+
};
384+
385+
// Only allow features whose feature gates have been enabled.
386+
let allowed = match feature_gate.as_ref().copied() {
387+
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
388+
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
389+
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
390+
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
391+
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
392+
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
393+
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
394+
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
395+
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
396+
Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
397+
Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
398+
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
399+
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
400+
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
401+
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
402+
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
403+
Some(name) => bug!("unknown target feature gate {}", name),
404+
None => true,
405+
};
406+
if !allowed {
407+
feature_err(
408+
&tcx.sess.parse_sess,
409+
feature_gate.unwrap(),
410+
item.span(),
411+
&format!("the target feature `{}` is currently unstable", feature),
412+
)
413+
.emit();
414+
}
415+
Some(Symbol::intern(feature))
416+
}));
417+
}
418+
}
419+
420+
/// Computes the set of target features used in a function for the purposes of
421+
/// inline assembly.
422+
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
423+
let mut target_features = tcx.sess.unstable_target_features.clone();
424+
if tcx.def_kind(did).has_codegen_attrs() {
425+
let attrs = tcx.codegen_fn_attrs(did);
426+
target_features.extend(&attrs.target_features);
427+
match attrs.instruction_set {
428+
None => {}
429+
Some(InstructionSetAttr::ArmA32) => {
430+
target_features.remove(&sym::thumb_mode);
431+
}
432+
Some(InstructionSetAttr::ArmT32) => {
433+
target_features.insert(sym::thumb_mode);
434+
}
435+
}
436+
}
437+
438+
tcx.arena.alloc(target_features)
439+
}
440+
441+
/// Checks the function annotated with `#[target_feature]` is not a safe
442+
/// trait method implementation, reporting an error if it is.
443+
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
444+
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
445+
let node = tcx.hir().get(hir_id);
446+
if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
447+
let parent_id = tcx.hir().get_parent_item(hir_id);
448+
let parent_item = tcx.hir().expect_item(parent_id.def_id);
449+
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
450+
tcx.sess
451+
.struct_span_err(
452+
attr_span,
453+
"`#[target_feature(..)]` cannot be applied to safe trait method",
454+
)
455+
.span_label(attr_span, "cannot be applied to safe trait method")
456+
.span_label(tcx.def_span(id), "not an `unsafe` function")
457+
.emit();
458+
}
459+
}
460+
}
461+
462+
pub(crate) fn provide(providers: &mut Providers) {
463+
*providers = Providers {
464+
supported_target_features: |tcx, cnum| {
465+
assert_eq!(cnum, LOCAL_CRATE);
466+
if tcx.sess.opts.actually_rustdoc {
467+
// rustdoc needs to be able to document functions that use all the features, so
468+
// whitelist them all
469+
all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
470+
} else {
471+
supported_target_features(tcx.sess)
472+
.iter()
473+
.map(|&(a, b)| (a.to_string(), b))
474+
.collect()
475+
}
476+
},
477+
asm_target_features,
478+
..*providers
479+
}
336480
}

compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,5 @@ codegen_ssa_archive_build_failure =
192192
193193
codegen_ssa_unknown_archive_kind =
194194
Don't know how to build archive of type: {$kind}
195+
196+
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`

compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ hir_analysis_extern_crate_not_idiomatic =
101101
`extern crate` is not idiomatic in the new edition
102102
.suggestion = convert it to a `{$msg_code}`
103103
104-
hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
105-
106104
hir_analysis_const_impl_for_non_const_trait =
107105
const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
108106
.suggestion = mark `{$trait_name}` as const

0 commit comments

Comments
 (0)