@@ -10,6 +10,7 @@ use rustc_session::lint::BuiltinLintDiag;
1010use rustc_session:: lint:: builtin:: UNEXPECTED_CFGS ;
1111use rustc_session:: parse:: feature_err;
1212use rustc_span:: { Span , Symbol , kw, sym} ;
13+ use rustc_target:: spec:: apple;
1314
1415use crate :: util:: UnsupportedLiteralReason ;
1516use crate :: { fluent_generated, parse_version, session_diagnostics} ;
@@ -150,6 +151,122 @@ pub fn eval_condition(
150151 RustcVersion :: CURRENT >= min_version
151152 }
152153 }
154+ ast:: MetaItemKind :: List ( mis) if cfg. name_or_empty ( ) == sym:: os_version_min => {
155+ try_gate_cfg ( sym:: os_version_min, cfg. span , sess, features) ;
156+
157+ let ( platform, version) = match & mis[ ..] {
158+ [ platform, version] => ( platform, version) ,
159+ [ ..] => {
160+ dcx. emit_err ( session_diagnostics:: ExpectedPlatformAndVersionLiterals {
161+ span : cfg. span ,
162+ } ) ;
163+ return false ;
164+ }
165+ } ;
166+
167+ let ( platform_sym, platform_span) = match platform {
168+ MetaItemInner :: Lit ( MetaItemLit {
169+ kind : LitKind :: Str ( platform_sym, ..) ,
170+ span : platform_span,
171+ ..
172+ } ) => ( platform_sym, platform_span) ,
173+ MetaItemInner :: Lit ( MetaItemLit { span, .. } )
174+ | MetaItemInner :: MetaItem ( MetaItem { span, .. } ) => {
175+ dcx. emit_err ( session_diagnostics:: ExpectedPlatformLiteral { span : * span } ) ;
176+ return false ;
177+ }
178+ } ;
179+
180+ let ( version_sym, version_span) = match version {
181+ MetaItemInner :: Lit ( MetaItemLit {
182+ kind : LitKind :: Str ( version_sym, ..) ,
183+ span : version_span,
184+ ..
185+ } ) => ( version_sym, version_span) ,
186+ MetaItemInner :: Lit ( MetaItemLit { span, .. } )
187+ | MetaItemInner :: MetaItem ( MetaItem { span, .. } ) => {
188+ dcx. emit_err ( session_diagnostics:: ExpectedVersionLiteral { span : * span } ) ;
189+ return false ;
190+ }
191+ } ;
192+
193+ // Always parse version, regardless of current target platform.
194+ let version = match * platform_sym {
195+ // Apple platforms follow the same versioning schema.
196+ sym:: macos | sym:: ios | sym:: tvos | sym:: watchos | sym:: visionos => {
197+ match version_sym. as_str ( ) . parse ( ) {
198+ Ok ( version) => {
199+ let os_min = apple:: OSVersion :: os_minimum_deployment_target (
200+ & platform_sym. as_str ( ) ,
201+ ) ;
202+
203+ // It's unnecessary to specify `cfg_target_os(...)` for a platform
204+ // version that is lower than the minimum targetted by `rustc` (instead,
205+ // make the item always available).
206+ //
207+ // This is correct _now_, but once we bump versions next time, we should
208+ // maybe make this a lint so that users can opt-in to supporting older
209+ // `rustc` versions? Or perhaps only fire the warning when Cargo's
210+ // `rust-version` field is above the version where the bump happened? Or
211+ // perhaps keep the version we check against low for a sufficiently long
212+ // time?
213+ if version <= os_min {
214+ sess. dcx ( ) . emit_warn (
215+ session_diagnostics:: AppleVersionUnnecessarilyLow {
216+ span : * version_span,
217+ os_min : os_min. fmt_pretty ( ) . to_string ( ) ,
218+ } ,
219+ ) ;
220+ // TODO(madsmtm): Add suggestion for replacing with `target_os = "..."`
221+ }
222+
223+ PlatformVersion :: Apple { os : * platform_sym, version }
224+ }
225+ Err ( error) => {
226+ sess. dcx ( ) . emit_err ( session_diagnostics:: AppleVersionInvalid {
227+ span : * version_span,
228+ error,
229+ } ) ;
230+ return false ;
231+ }
232+ }
233+ }
234+ // FIXME(madsmtm): Handle further platforms as specified in the RFC.
235+ sym:: windows | sym:: libc => {
236+ #[ allow( rustc:: untranslatable_diagnostic) ] // Temporary
237+ dcx. span_err ( * platform_span, "unimplemented platform" ) ;
238+ return false ;
239+ }
240+ _ => {
241+ // Unknown platform. This is intentionally a warning (and not an error) to be
242+ // future-compatible with later additions.
243+ let known_platforms = [
244+ sym:: macos,
245+ sym:: ios,
246+ sym:: tvos,
247+ sym:: watchos,
248+ sym:: visionos,
249+ // sym::windows,
250+ // sym::libc,
251+ ] ;
252+ dcx. emit_warn ( session_diagnostics:: UnknownPlatformLiteral {
253+ span : * platform_span,
254+ possibilities : known_platforms. into_iter ( ) . collect ( ) ,
255+ } ) ;
256+ return false ;
257+ }
258+ } ;
259+
260+ // Figure out actual cfg-status based on current platform.
261+ match version {
262+ PlatformVersion :: Apple { os, version } if os. as_str ( ) == sess. target . os => {
263+ let deployment_target = sess. apple_deployment_target ( ) ;
264+ version <= deployment_target
265+ }
266+ // If a `cfg`-value does not apply to a specific platform, assume
267+ _ => false ,
268+ }
269+ }
153270 ast:: MetaItemKind :: List ( mis) => {
154271 for mi in mis. iter ( ) {
155272 if mi. meta_item_or_bool ( ) . is_none ( ) {
@@ -251,3 +368,8 @@ pub fn eval_condition(
251368 }
252369 }
253370}
371+
372+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
373+ enum PlatformVersion {
374+ Apple { os : Symbol , version : apple:: OSVersion } ,
375+ }
0 commit comments