@@ -10,7 +10,7 @@ use rustc_middle::query::Providers;
1010use rustc_middle:: ty:: TyCtxt ;
1111use rustc_session:: parse:: feature_err;
1212use rustc_span:: { Span , Symbol , sym} ;
13- use rustc_target:: target_features;
13+ use rustc_target:: target_features:: { self , Stability } ;
1414
1515use crate :: errors;
1616
@@ -87,10 +87,7 @@ pub(crate) fn from_target_feature_attr(
8787 // But ensure the ABI does not forbid enabling this.
8888 // Here we do assume that LLVM doesn't add even more implied features
8989 // 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 ( ) ) {
9491 tcx. dcx ( ) . emit_err ( errors:: ForbiddenTargetFeatureAttr {
9592 span : item. span ( ) ,
9693 feature : name. as_str ( ) ,
@@ -146,13 +143,37 @@ pub(crate) fn provide(providers: &mut Providers) {
146143 assert_eq ! ( cnum, LOCAL_CRATE ) ;
147144 if tcx. sess . opts . actually_rustdoc {
148145 // 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
156177 } else {
157178 tcx. sess
158179 . target
0 commit comments