@@ -10,7 +10,7 @@ use rustc_middle::query::Providers;
10
10
use rustc_middle:: ty:: TyCtxt ;
11
11
use rustc_session:: parse:: feature_err;
12
12
use rustc_span:: { Span , Symbol , sym} ;
13
- use rustc_target:: target_features;
13
+ use rustc_target:: target_features:: { self , Stability } ;
14
14
15
15
use crate :: errors;
16
16
@@ -87,10 +87,7 @@ pub(crate) fn from_target_feature_attr(
87
87
// But ensure the ABI does not forbid enabling this.
88
88
// Here we do assume that LLVM doesn't add even more implied features
89
89
// we don't know about, at least no features that would have ABI effects!
90
- // We skip this check in rustdoc, like we skip all target feature related checks.
91
- if !tcx. sess . opts . actually_rustdoc
92
- && abi_feature_constraints. incompatible . contains ( & name. as_str ( ) )
93
- {
90
+ if abi_feature_constraints. incompatible . contains ( & name. as_str ( ) ) {
94
91
tcx. dcx ( ) . emit_err ( errors:: ForbiddenTargetFeatureAttr {
95
92
span : item. span ( ) ,
96
93
feature : name. as_str ( ) ,
@@ -146,13 +143,37 @@ pub(crate) fn provide(providers: &mut Providers) {
146
143
assert_eq ! ( cnum, LOCAL_CRATE ) ;
147
144
if tcx. sess . opts . actually_rustdoc {
148
145
// HACK: rustdoc would like to pretend that we have all the target features, so we
149
- // have to merge all the lists into one. The result has a "random" stability
150
- // (depending on the order in which we consider features); all places that check
151
- // target stability are expected to check `actually_rustdoc` and do nothing when
152
- // that is set.
153
- rustc_target:: target_features:: all_rust_features ( )
154
- . map ( |( a, b) | ( a. to_string ( ) , b) )
155
- . collect ( )
146
+ // have to merge all the lists into one. To ensure an unstable target never prevents
147
+ // a stable one from working, we merge the stability info of all instances of the
148
+ // same target feature name, with the "most stable" taking precedence. And then we
149
+ // hope that this doesn't cause issues anywhere else in the compiler...
150
+ let mut result: UnordMap < String , Stability > = Default :: default ( ) ;
151
+ for ( name, stability) in rustc_target:: target_features:: all_rust_features ( ) {
152
+ use std:: collections:: hash_map:: Entry ;
153
+ match result. entry ( name. to_owned ( ) ) {
154
+ Entry :: Vacant ( vacant_entry) => {
155
+ vacant_entry. insert ( stability) ;
156
+ }
157
+ Entry :: Occupied ( mut occupied_entry) => {
158
+ // Merge the two stabilities, "more stable" taking precedence.
159
+ match ( occupied_entry. get ( ) , stability) {
160
+ ( Stability :: Stable , _)
161
+ | (
162
+ Stability :: Unstable { .. } ,
163
+ Stability :: Unstable { .. } | Stability :: Forbidden { .. } ,
164
+ )
165
+ | ( Stability :: Forbidden { .. } , Stability :: Forbidden { .. } ) => {
166
+ // The stability in the entry is at least as good as the new one, just keep it.
167
+ }
168
+ _ => {
169
+ // Overwrite stabilite.
170
+ occupied_entry. insert ( stability) ;
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+ result
156
177
} else {
157
178
tcx. sess
158
179
. target
0 commit comments