@@ -10,6 +10,7 @@ use rustc_session::lint::BuiltinLintDiag;
10
10
use rustc_session:: lint:: builtin:: UNEXPECTED_CFGS ;
11
11
use rustc_session:: parse:: feature_err;
12
12
use rustc_span:: { Span , Symbol , kw, sym} ;
13
+ use rustc_target:: spec:: apple;
13
14
14
15
use crate :: util:: UnsupportedLiteralReason ;
15
16
use crate :: { fluent_generated, parse_version, session_diagnostics} ;
@@ -150,6 +151,122 @@ pub fn eval_condition(
150
151
RustcVersion :: CURRENT >= min_version
151
152
}
152
153
}
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
+ }
153
270
ast:: MetaItemKind :: List ( mis) => {
154
271
for mi in mis. iter ( ) {
155
272
if mi. meta_item_or_bool ( ) . is_none ( ) {
@@ -251,3 +368,8 @@ pub fn eval_condition(
251
368
}
252
369
}
253
370
}
371
+
372
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
373
+ enum PlatformVersion {
374
+ Apple { os : Symbol , version : apple:: OSVersion } ,
375
+ }
0 commit comments