Skip to content

Commit e4682f6

Browse files
authored
Unrolled build for #145573
Rollup merge of #145573 - veluca93:unsafe-force-target-feature, r=davidtwco Add an experimental unsafe(force_target_feature) attribute. This uses the feature gate for #143352, but is described in rust-lang/rfcs#3820 which is strongly tied to the experiment.
2 parents 78b89eb + 291da71 commit e4682f6

File tree

21 files changed

+262
-61
lines changed

21 files changed

+262
-61
lines changed

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1596,7 +1596,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15961596
let safety = self.lower_safety(h.safety, default_safety);
15971597

15981598
// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
1599-
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. })
1599+
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { was_forced: false, .. })
16001600
&& safety.is_safe()
16011601
&& !self.tcx.sess.target.is_like_wasm
16021602
{

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 78 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -376,57 +376,68 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
376376
}
377377
}
378378

379+
fn parse_tf_attribute<'c, S: Stage>(
380+
cx: &'c mut AcceptContext<'_, '_, S>,
381+
args: &'c ArgParser<'_>,
382+
) -> impl IntoIterator<Item = (Symbol, Span)> + 'c {
383+
let mut features = Vec::new();
384+
let ArgParser::List(list) = args else {
385+
cx.expected_list(cx.attr_span);
386+
return features;
387+
};
388+
if list.is_empty() {
389+
cx.warn_empty_attribute(cx.attr_span);
390+
return features;
391+
}
392+
for item in list.mixed() {
393+
let Some(name_value) = item.meta_item() else {
394+
cx.expected_name_value(item.span(), Some(sym::enable));
395+
return features;
396+
};
397+
398+
// Validate name
399+
let Some(name) = name_value.path().word_sym() else {
400+
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
401+
return features;
402+
};
403+
if name != sym::enable {
404+
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
405+
return features;
406+
}
407+
408+
// Use value
409+
let Some(name_value) = name_value.args().name_value() else {
410+
cx.expected_name_value(item.span(), Some(sym::enable));
411+
return features;
412+
};
413+
let Some(value_str) = name_value.value_as_str() else {
414+
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
415+
return features;
416+
};
417+
for feature in value_str.as_str().split(",") {
418+
features.push((Symbol::intern(feature), item.span()));
419+
}
420+
}
421+
features
422+
}
423+
379424
pub(crate) struct TargetFeatureParser;
380425

381426
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
382427
type Item = (Symbol, Span);
383428
const PATH: &[Symbol] = &[sym::target_feature];
384-
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
429+
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
430+
features: items,
431+
attr_span: span,
432+
was_forced: false,
433+
};
385434
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
386435

387436
fn extend<'c>(
388437
cx: &'c mut AcceptContext<'_, '_, S>,
389438
args: &'c ArgParser<'_>,
390439
) -> impl IntoIterator<Item = Self::Item> + 'c {
391-
let mut features = Vec::new();
392-
let ArgParser::List(list) = args else {
393-
cx.expected_list(cx.attr_span);
394-
return features;
395-
};
396-
if list.is_empty() {
397-
cx.warn_empty_attribute(cx.attr_span);
398-
return features;
399-
}
400-
for item in list.mixed() {
401-
let Some(name_value) = item.meta_item() else {
402-
cx.expected_name_value(item.span(), Some(sym::enable));
403-
return features;
404-
};
405-
406-
// Validate name
407-
let Some(name) = name_value.path().word_sym() else {
408-
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
409-
return features;
410-
};
411-
if name != sym::enable {
412-
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
413-
return features;
414-
}
415-
416-
// Use value
417-
let Some(name_value) = name_value.args().name_value() else {
418-
cx.expected_name_value(item.span(), Some(sym::enable));
419-
return features;
420-
};
421-
let Some(value_str) = name_value.value_as_str() else {
422-
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
423-
return features;
424-
};
425-
for feature in value_str.as_str().split(",") {
426-
features.push((Symbol::intern(feature), item.span()));
427-
}
428-
}
429-
features
440+
parse_tf_attribute(cx, args)
430441
}
431442

432443
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
@@ -440,3 +451,30 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
440451
Warn(Target::MacroDef),
441452
]);
442453
}
454+
455+
pub(crate) struct ForceTargetFeatureParser;
456+
457+
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
458+
type Item = (Symbol, Span);
459+
const PATH: &[Symbol] = &[sym::force_target_feature];
460+
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
461+
features: items,
462+
attr_span: span,
463+
was_forced: true,
464+
};
465+
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
466+
467+
fn extend<'c>(
468+
cx: &'c mut AcceptContext<'_, '_, S>,
469+
args: &'c ArgParser<'_>,
470+
) -> impl IntoIterator<Item = Self::Item> + 'c {
471+
parse_tf_attribute(cx, args)
472+
}
473+
474+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
475+
Allow(Target::Fn),
476+
Allow(Target::Method(MethodKind::Inherent)),
477+
Allow(Target::Method(MethodKind::Trait { body: true })),
478+
Allow(Target::Method(MethodKind::TraitImpl)),
479+
]);
480+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use crate::attributes::allow_unstable::{
1919
};
2020
use crate::attributes::body::CoroutineParser;
2121
use crate::attributes::codegen_attrs::{
22-
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
23-
TargetFeatureParser, TrackCallerParser, UsedParser,
22+
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
23+
NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
2424
};
2525
use crate::attributes::confusables::ConfusablesParser;
2626
use crate::attributes::deprecation::DeprecationParser;
@@ -157,6 +157,7 @@ attribute_parsers!(
157157
// tidy-alphabetical-start
158158
Combine<AllowConstFnUnstableParser>,
159159
Combine<AllowInternalUnstableParser>,
160+
Combine<ForceTargetFeatureParser>,
160161
Combine<ReprParser>,
161162
Combine<TargetFeatureParser>,
162163
Combine<UnstableFeatureBoundParser>,

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,15 @@ fn process_builtin_attrs(
193193
}
194194
}
195195
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
196-
AttributeKind::TargetFeature(features, attr_span) => {
196+
AttributeKind::TargetFeature { features, attr_span, was_forced } => {
197197
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
198198
tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
199199
continue;
200200
};
201201
let safe_target_features =
202202
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
203203
codegen_fn_attrs.safe_target_features = safe_target_features;
204-
if safe_target_features {
204+
if safe_target_features && !was_forced {
205205
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
206206
// The `#[target_feature]` attribute is allowed on
207207
// WebAssembly targets on all functions. Prior to stabilizing
@@ -232,6 +232,7 @@ fn process_builtin_attrs(
232232
tcx,
233233
did,
234234
features,
235+
*was_forced,
235236
rust_target_features,
236237
&mut codegen_fn_attrs.target_features,
237238
);
@@ -462,7 +463,7 @@ fn check_result(
462463
.collect(),
463464
) {
464465
let span =
465-
find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span)
466+
find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature{attr_span: span, ..} => *span)
466467
.unwrap_or_else(|| tcx.def_span(did));
467468

468469
tcx.dcx()

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
33
use rustc_hir::attrs::InstructionSetAttr;
44
use rustc_hir::def::DefKind;
55
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
6-
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
6+
use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
77
use rustc_middle::query::Providers;
88
use rustc_middle::ty::TyCtxt;
99
use rustc_session::Session;
@@ -22,6 +22,7 @@ pub(crate) fn from_target_feature_attr(
2222
tcx: TyCtxt<'_>,
2323
did: LocalDefId,
2424
features: &[(Symbol, Span)],
25+
was_forced: bool,
2526
rust_target_features: &UnordMap<String, target_features::Stability>,
2627
target_features: &mut Vec<TargetFeature>,
2728
) {
@@ -88,7 +89,14 @@ pub(crate) fn from_target_feature_attr(
8889
}
8990
}
9091
}
91-
target_features.push(TargetFeature { name, implied: name != feature })
92+
let kind = if name != feature {
93+
TargetFeatureKind::Implied
94+
} else if was_forced {
95+
TargetFeatureKind::Forced
96+
} else {
97+
TargetFeatureKind::Enabled
98+
};
99+
target_features.push(TargetFeature { name, kind })
92100
}
93101
}
94102
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
744744
template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
745745
ErrorPreceding, EncodeCrossCrate::No
746746
),
747+
gated!(
748+
unsafe force_target_feature, Normal, template!(List: &[r#"enable = "name""#]),
749+
DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature)
750+
),
747751
gated!(
748752
sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
749753
EncodeCrossCrate::No, sanitize, experimental!(sanitize),

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,8 @@ declare_features! (
480480
(unstable, doc_cfg_hide, "1.57.0", Some(43781)),
481481
/// Allows `#[doc(masked)]`.
482482
(unstable, doc_masked, "1.21.0", Some(44027)),
483+
/// Allows features to allow target_feature to better interact with traits.
484+
(incomplete, effective_target_features, "CURRENT_RUSTC_VERSION", Some(143352)),
483485
/// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }`
484486
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
485487
/// Allows exhaustive pattern matching on types that contain uninhabited types.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,9 @@ pub enum AttributeKind {
524524
/// Represents `#[rustc_std_internal_symbol]`.
525525
StdInternalSymbol(Span),
526526

527-
/// Represents `#[target_feature(enable = "...")]`
528-
TargetFeature(ThinVec<(Symbol, Span)>, Span),
527+
/// Represents `#[target_feature(enable = "...")]` and
528+
/// `#[unsafe(force_target_feature(enable = "...")]`.
529+
TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },
529530

530531
/// Represents `#[track_caller]`
531532
TrackCaller(Span),

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl AttributeKind {
7878
SpecializationTrait(..) => No,
7979
Stability { .. } => Yes,
8080
StdInternalSymbol(..) => No,
81-
TargetFeature(..) => No,
81+
TargetFeature { .. } => No,
8282
TrackCaller(..) => Yes,
8383
TypeConst(..) => Yes,
8484
UnsafeSpecializationMarker(..) => No,

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,23 @@ pub struct CodegenFnAttrs {
7272
pub patchable_function_entry: Option<PatchableFunctionEntry>,
7373
}
7474

75+
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)]
76+
pub enum TargetFeatureKind {
77+
/// The feature is implied by another feature, rather than explicitly added by the
78+
/// `#[target_feature]` attribute
79+
Implied,
80+
/// The feature is added by the regular `target_feature` attribute.
81+
Enabled,
82+
/// The feature is added by the unsafe `force_target_feature` attribute.
83+
Forced,
84+
}
85+
7586
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
7687
pub struct TargetFeature {
7788
/// The name of the target feature (e.g. "avx")
7889
pub name: Symbol,
79-
/// The feature is implied by another feature, rather than explicitly added by the
80-
/// `#[target_feature]` attribute
81-
pub implied: bool,
90+
/// The way this feature was enabled.
91+
pub kind: TargetFeatureKind,
8292
}
8393

8494
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]

0 commit comments

Comments
 (0)