Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 291da71

Browse files
committed
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.
1 parent 6ba0ce4 commit 291da71

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
@@ -385,57 +385,68 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
385385
}
386386
}
387387

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

390435
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
391436
type Item = (Symbol, Span);
392437
const PATH: &[Symbol] = &[sym::target_feature];
393-
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
438+
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
439+
features: items,
440+
attr_span: span,
441+
was_forced: false,
442+
};
394443
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
395444

396445
fn extend<'c>(
397446
cx: &'c mut AcceptContext<'_, '_, S>,
398447
args: &'c ArgParser<'_>,
399448
) -> impl IntoIterator<Item = Self::Item> + 'c {
400-
let mut features = Vec::new();
401-
let ArgParser::List(list) = args else {
402-
cx.expected_list(cx.attr_span);
403-
return features;
404-
};
405-
if list.is_empty() {
406-
cx.warn_empty_attribute(cx.attr_span);
407-
return features;
408-
}
409-
for item in list.mixed() {
410-
let Some(name_value) = item.meta_item() else {
411-
cx.expected_name_value(item.span(), Some(sym::enable));
412-
return features;
413-
};
414-
415-
// Validate name
416-
let Some(name) = name_value.path().word_sym() else {
417-
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
418-
return features;
419-
};
420-
if name != sym::enable {
421-
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
422-
return features;
423-
}
424-
425-
// Use value
426-
let Some(name_value) = name_value.args().name_value() else {
427-
cx.expected_name_value(item.span(), Some(sym::enable));
428-
return features;
429-
};
430-
let Some(value_str) = name_value.value_as_str() else {
431-
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
432-
return features;
433-
};
434-
for feature in value_str.as_str().split(",") {
435-
features.push((Symbol::intern(feature), item.span()));
436-
}
437-
}
438-
features
449+
parse_tf_attribute(cx, args)
439450
}
440451

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

‎compiler/rustc_attr_parsing/src/context.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use crate::attributes::allow_unstable::{
2121
};
2222
use crate::attributes::body::CoroutineParser;
2323
use crate::attributes::codegen_attrs::{
24-
ColdParser, CoverageParser, ExportNameParser, NakedParser,NoMangleParser,OptimizeParser,
25-
TargetFeatureParser, TrackCallerParser, UsedParser,
24+
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser,NakedParser,
25+
NoMangleParser,OptimizeParser,TargetFeatureParser, TrackCallerParser, UsedParser,
2626
};
2727
use crate::attributes::confusables::ConfusablesParser;
2828
use crate::attributes::deprecation::DeprecationParser;
@@ -161,6 +161,7 @@ attribute_parsers!(
161161
// tidy-alphabetical-start
162162
Combine<AllowConstFnUnstableParser>,
163163
Combine<AllowInternalUnstableParser>,
164+
Combine<ForceTargetFeatureParser>,
164165
Combine<ReprParser>,
165166
Combine<TargetFeatureParser>,
166167
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)

AltStyle によって変換されたページ (->オリジナル) /