|
| 1 | +use std::iter::FromIterator; |
| 2 | + |
1 | 3 | #[cfg(feature = "master")] |
2 | 4 | use gccjit::Context; |
3 | 5 | use rustc_codegen_ssa::codegen_attrs::check_tied_features; |
4 | 6 | use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable; |
5 | | -use rustc_data_structures::fx::FxHashMap; |
6 | | -userustc_middle::bug; |
| 7 | +use rustc_data_structures::fx::{FxHashMap,FxHashSet}; |
| 8 | +userustc_data_structures::unord::UnordSet; |
7 | 9 | use rustc_session::Session; |
8 | 10 | use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; |
9 | 11 | use smallvec::{SmallVec, smallvec}; |
@@ -37,82 +39,137 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri |
37 | 39 | letmut features = vec![]; |
38 | 40 |
|
39 | 41 | // Features implied by an implicit or explicit `--target`. |
40 | | - features.extend( |
41 | | - sess.target |
42 | | -.features |
43 | | -.split(',') |
44 | | -.filter(|v| !v.is_empty() && backend_feature_name(v).is_some()) |
45 | | -.map(String::from), |
46 | | -); |
| 42 | + features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from)); |
47 | 43 |
|
48 | 44 | // -Ctarget-features |
49 | 45 | let known_features = sess.target.rust_target_features(); |
50 | 46 | letmut featsmap = FxHashMap::default(); |
51 | | -let feats = sess |
52 | | -.opts |
53 | | -.cg |
54 | | -.target_feature |
55 | | -.split(',') |
56 | | -.filter_map(|s| { |
57 | | -let enable_disable = match s.chars().next(){ |
58 | | -None => returnNone, |
59 | | -Some(c @ ('+' | '-')) => c, |
60 | | -Some(_) => { |
61 | | -if diagnostics { |
62 | | - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix{feature: s }); |
63 | | -} |
64 | | -returnNone; |
65 | | -} |
66 | | -}; |
67 | 47 |
|
68 | | -// Get the backend feature name, if any. |
69 | | -// This excludes rustc-specific features, that do not get passed down to GCC. |
70 | | -let feature = backend_feature_name(s)?; |
71 | | -// Warn against use of GCC specific feature names on the CLI. |
| 48 | +// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones |
| 49 | +// are disabled. |
| 50 | +let abi_feature_constraints = sess.target.abi_required_features(); |
| 51 | +let abi_incompatible_set = |
| 52 | +FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied()); |
| 53 | + |
| 54 | +// Compute implied features |
| 55 | +letmut all_rust_features = vec![]; |
| 56 | +for feature in sess.opts.cg.target_feature.split(','){ |
| 57 | +ifletSome(feature) = feature.strip_prefix('+'){ |
| 58 | + all_rust_features.extend( |
| 59 | +UnordSet::from(sess.target.implied_target_features(std::iter::once(feature))) |
| 60 | +.to_sorted_stable_ord() |
| 61 | +.iter() |
| 62 | +.map(|&&s| (true, s)), |
| 63 | +) |
| 64 | +}elseifletSome(feature) = feature.strip_prefix('-'){ |
| 65 | +// FIXME: Why do we not remove implied features on "-" here? |
| 66 | +// We do the equivalent above in `target_features_cfg`. |
| 67 | +// See <https://github.com/rust-lang/rust/issues/134792>. |
| 68 | + all_rust_features.push((false, feature)); |
| 69 | +}elseif !feature.is_empty(){ |
72 | 70 | if diagnostics { |
73 | | -let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); |
74 | | -match feature_state { |
75 | | -None => { |
76 | | -let rust_feature = |
77 | | - known_features.iter().find_map(|&(rust_feature, _, _)| { |
78 | | -let gcc_features = to_gcc_features(sess, rust_feature); |
79 | | -if gcc_features.contains(&feature) |
80 | | - && !gcc_features.contains(&rust_feature) |
81 | | -{ |
82 | | -Some(rust_feature) |
83 | | -}else{ |
84 | | -None |
85 | | -} |
86 | | -}); |
87 | | -let unknown_feature = ifletSome(rust_feature) = rust_feature { |
88 | | -UnknownCTargetFeature{ |
89 | | - feature, |
90 | | -rust_feature:PossibleFeature::Some{ rust_feature }, |
91 | | -} |
92 | | -}else{ |
93 | | -UnknownCTargetFeature{ feature,rust_feature:PossibleFeature::None} |
94 | | -}; |
95 | | - sess.dcx().emit_warn(unknown_feature); |
96 | | -} |
97 | | -Some((_, stability, _)) => { |
98 | | -ifletErr(reason) = |
99 | | - stability.toggle_allowed(&sess.target, enable_disable == '+') |
| 71 | + sess.dcx().emit_warn(UnknownCTargetFeaturePrefix{ feature }); |
| 72 | +} |
| 73 | +} |
| 74 | +} |
| 75 | +// Remove features that are meant for rustc, not codegen. |
| 76 | + all_rust_features.retain(|(_, feature)| { |
| 77 | +// Retain if it is not a rustc feature |
| 78 | + !RUSTC_SPECIFIC_FEATURES.contains(feature) |
| 79 | +}); |
| 80 | + |
| 81 | +// Check feature validity. |
| 82 | +if diagnostics { |
| 83 | +for&(enable, feature)in&all_rust_features { |
| 84 | +let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); |
| 85 | +match feature_state { |
| 86 | +None => { |
| 87 | +let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { |
| 88 | +let gcc_features = to_gcc_features(sess, rust_feature); |
| 89 | +if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) |
100 | 90 | { |
101 | | - sess.dcx().emit_warn(ForbiddenCTargetFeature{ feature, reason }); |
102 | | -}elseif stability.requires_nightly().is_some(){ |
103 | | -// An unstable feature. Warn about using it. (It makes little sense |
104 | | -// to hard-error here since we just warn about fully unknown |
105 | | -// features above). |
106 | | - sess.dcx().emit_warn(UnstableCTargetFeature{ feature }); |
| 91 | +Some(rust_feature) |
| 92 | +}else{ |
| 93 | +None |
107 | 94 | } |
| 95 | +}); |
| 96 | +let unknown_feature = ifletSome(rust_feature) = rust_feature { |
| 97 | +UnknownCTargetFeature{ |
| 98 | + feature, |
| 99 | +rust_feature:PossibleFeature::Some{ rust_feature }, |
| 100 | +} |
| 101 | +}else{ |
| 102 | +UnknownCTargetFeature{ feature,rust_feature:PossibleFeature::None} |
| 103 | +}; |
| 104 | + sess.dcx().emit_warn(unknown_feature); |
| 105 | +} |
| 106 | +Some((_, stability, _)) => { |
| 107 | +ifletErr(reason) = stability.toggle_allowed(){ |
| 108 | + sess.dcx().emit_warn(ForbiddenCTargetFeature{ |
| 109 | + feature, |
| 110 | +enabled:if enable {"enabled"}else{"disabled"}, |
| 111 | + reason, |
| 112 | +}); |
| 113 | +}elseif stability.requires_nightly().is_some(){ |
| 114 | +// An unstable feature. Warn about using it. (It makes little sense |
| 115 | +// to hard-error here since we just warn about fully unknown |
| 116 | +// features above). |
| 117 | + sess.dcx().emit_warn(UnstableCTargetFeature{ feature }); |
108 | 118 | } |
109 | 119 | } |
| 120 | +} |
110 | 121 |
|
111 | | -// FIXME(nagisa): figure out how to not allocate a full hashset here. |
112 | | - featsmap.insert(feature, enable_disable == '+'); |
| 122 | +// Ensure that the features we enable/disable are compatible with the ABI. |
| 123 | +if enable { |
| 124 | +if abi_incompatible_set.contains(feature){ |
| 125 | + sess.dcx().emit_warn(ForbiddenCTargetFeature{ |
| 126 | + feature, |
| 127 | +enabled:"enabled", |
| 128 | +reason:"this feature is incompatible with the target ABI", |
| 129 | +}); |
| 130 | +} |
| 131 | +}else{ |
| 132 | +// FIXME: we have to request implied features here since |
| 133 | +// negative features do not handle implied features above. |
| 134 | +for&required in abi_feature_constraints.required.iter(){ |
| 135 | +let implied = sess.target.implied_target_features(std::iter::once(required)); |
| 136 | +if implied.contains(feature){ |
| 137 | + sess.dcx().emit_warn(ForbiddenCTargetFeature{ |
| 138 | + feature, |
| 139 | +enabled:"disabled", |
| 140 | +reason:"this feature is required by the target ABI", |
| 141 | +}); |
| 142 | +} |
| 143 | +} |
113 | 144 | } |
114 | 145 |
|
115 | | -// ... otherwise though we run through `to_gcc_features` when |
| 146 | +// FIXME(nagisa): figure out how to not allocate a full hashset here. |
| 147 | + featsmap.insert(feature, enable); |
| 148 | +} |
| 149 | +} |
| 150 | + |
| 151 | +// To be sure the ABI-relevant features are all in the right state, we explicitly |
| 152 | +// (un)set them here. This means if the target spec sets those features wrong, |
| 153 | +// we will silently correct them rather than silently producing wrong code. |
| 154 | +// (The target sanity check tries to catch this, but we can't know which features are |
| 155 | +// enabled in GCC by default so we can't be fully sure about that check.) |
| 156 | +// We add these at the beginning of the list so that `-Ctarget-features` can |
| 157 | +// still override it... that's unsound, but more compatible with past behavior. |
| 158 | + all_rust_features.splice( |
| 159 | +0..0, |
| 160 | + abi_feature_constraints |
| 161 | +.required |
| 162 | +.iter() |
| 163 | +.map(|&f| (true, f)) |
| 164 | +.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))), |
| 165 | +); |
| 166 | + |
| 167 | +// Translate this into GCC features. |
| 168 | +let feats = all_rust_features |
| 169 | +.iter() |
| 170 | +.filter_map(|&(enable, feature)| { |
| 171 | +let enable_disable = if enable {'+'}else{'-'}; |
| 172 | +// We run through `to_gcc_features` when |
116 | 173 | // passing requests down to GCC. This means that all in-language |
117 | 174 | // features also work on the command line instead of having two |
118 | 175 | // different names when the GCC name and the Rust name differ. |
@@ -146,26 +203,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri |
146 | 203 | features |
147 | 204 | } |
148 | 205 |
|
149 | | -/// Returns a feature name for the given `+feature` or `-feature` string. |
150 | | -/// |
151 | | -/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].) |
152 | | -fnbackend_feature_name(s:&str) -> Option<&str>{ |
153 | | -// features must start with a `+` or `-`. |
154 | | -let feature = s.strip_prefix(&['+','-'][..]).unwrap_or_else(|| { |
155 | | -bug!("target feature `{}` must begin with a `+` or `-`", s); |
156 | | -}); |
157 | | -// Rustc-specific feature requests like `+crt-static` or `-crt-static` |
158 | | -// are not passed down to GCC. |
159 | | -ifRUSTC_SPECIFIC_FEATURES.contains(&feature){ |
160 | | -returnNone; |
161 | | -} |
162 | | -Some(feature) |
163 | | -} |
164 | | - |
165 | 206 | // To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html |
166 | 207 | pubfnto_gcc_features<'a>(sess:&Session,s:&'astr) -> SmallVec<[&'astr;2]>{ |
167 | 208 | let arch = if sess.target.arch == "x86_64"{"x86"}else{&*sess.target.arch}; |
168 | 209 | match(arch, s){ |
| 210 | +// FIXME: seems like x87 does not exist? |
| 211 | +("x86","x87") => smallvec![], |
169 | 212 | ("x86","sse4.2") => smallvec!["sse4.2","crc32"], |
170 | 213 | ("x86","pclmulqdq") => smallvec!["pclmul"], |
171 | 214 | ("x86","rdrand") => smallvec!["rdrnd"], |
|
0 commit comments