-
-
Notifications
You must be signed in to change notification settings - Fork 103
Description
As of Rust 1.86, #[target_feature]
can be applied to safe functions, so we should look at what it means in terms of breaking changes.
Reading the reference page for this attribute is highly recommended before proceeding with this issue.
Adding #[target_feature]
to a safe pub function that didn't have it before is a major breaking change, since the function no longer implements its corresponding Fn()
trait — playground
- lint for functions (deny by default): Add
safe_function_target_feature_added
lint #1303 - lint for
ImplOwner
methods (deny by default): Addsafe_inherent_method_target_feature_added
lint #1306 - currently prohibited for safe functions in traits; no lint there
Adding #[target_feature]
to a unsafe pub function that didn't have it before is usually a major breaking change, since the safety obligations for that function have changed. The exception is if the newly-requested feature was already enabled on that target, or it's implied by another already-requested feature. For example: x86-64 with any OS at all enables sse
and sse2
by default, and avx2
implies avx
. Information on whether required features are explicit or implied, or globally enabled, is available in the schema.
- lint for functions (deny by default): Add
unsafe_function_target_feature_added
lint #1302 - lint for
ImplOwner
methods (deny by default): Addunsafe_inherent_method_target_feature_added
lint #1307 - lint for trait associated functions / methods (deny by default): Add
unsafe_trait_method_target_feature_added
lint #1304
If a safe pub function already had #[target_feature]
, adding a new feature is always a major breaking change. This lint shouldn't trigger if the function became unsafe
as well — that breakage dominates.
- lint for functions (deny by default): Add safe_function_requires_more_target_features lint #1332
- lint for
ImplOwner
methods (deny by default): Add safe_inherent_method_requires_more_target_features lint #1333 - currently prohibited in safe functions in traits; no lint here
If an unsafe pub function already had #[target_feature]
, adding a new feature is only major breaking if the feature isn't implied nor already globally enabled, as above. This lint should trigger even if the function might have become safe in the meantime.
- lint for functions (deny by default): Add
function_requires_more_target_features
lint #1316 - lint for
ImplOwner
methods (deny by default): Add lint for inherent methods gaining target features #1311 - lint for trait associated functions / methods (deny by default): Add
trait_method_requires_more_target_features
lint #1315
If an unsealed trait's associated function has a feature removed from its existing #[target_feature]
list, that's a major breaking change since Rust currently allows impls of that trait to specify a stricter (i.e. the previous) #[target_feature]
without any warning. Such downstream impls may suddenly be hit with UB when a caller that uses impl Trait
or dyn Trait
with their impl (with stricter target feature requirements) is used based on the trait's looser declared target feature requirements. The exception to the breakage is when the removed feature continues to be implied by either the platform (see above x86-64 example) or by another feature that remains declared.
- lint for unsealed trait associated functions / methods (deny by default): Add trait_method_target_feature_removed lint #1337
- lint for public API sealed trait associated functions / methods (warn by default): Add
pub_api_sealed_trait_method_target_feature_removed
lint. #1339
Related false-positives
#[target_feature]
also appears to trigger a bug in rustdoc JSON that causes false-positives in two of our lints: function_unsafe_added
and inherent_method_unsafe_added
. The cause is this: rust-lang/rust#142655
Open questions
How do we find out which features are effectively implied by which target? This seems to be one of those things that "everyone knows" but isn't really written down directly in that explicit form.(answered below)How do we figure out which target's "implied" rules we should be looking at incargo-semver-checks
? We may have to askrustdoc
to describe the target while generating rustdoc JSON.How do we encode the "implies" rules? Do we put them in the schema (as "adapter magic"), or do we make some wild pile of regexes, or something else?(answered below)- With regard to the above, how will we handle cases when new features are added to the list? We may only support target features that are considered stable (i.e. "unstable features don't auto-enable any other features and are never automatically enabled themselves"), and rely on stabilization announcements to be notified of changes.