1
1
use rustc_ast:: { LitKind , MetaItem , MetaItemInner , MetaItemKind , MetaItemLit , NodeId } ;
2
2
use rustc_ast_pretty:: pprust;
3
3
use rustc_attr_data_structures:: RustcVersion ;
4
+ use rustc_errors:: Applicability ;
4
5
use rustc_feature:: { Features , GatedCfg , find_gated_cfg} ;
5
6
use rustc_session:: Session ;
6
7
use rustc_session:: config:: ExpectedValues ;
@@ -9,6 +10,7 @@ use rustc_session::lint::builtin::UNEXPECTED_CFGS;
9
10
use rustc_session:: parse:: feature_err;
10
11
use rustc_span:: symbol:: kw;
11
12
use rustc_span:: { Span , Symbol , sym} ;
13
+ use rustc_target:: spec:: apple;
12
14
13
15
use crate :: session_diagnostics:: { self , UnsupportedLiteralReason } ;
14
16
use crate :: { fluent_generated, parse_version} ;
@@ -149,6 +151,129 @@ pub fn eval_condition(
149
151
RustcVersion :: CURRENT >= min_version
150
152
}
151
153
}
154
+ 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 ( )
215
+ . create_warn (
216
+ session_diagnostics:: AppleVersionUnnecessarilyLow {
217
+ span : * version_span,
218
+ os_min : os_min. fmt_pretty ( ) . to_string ( ) ,
219
+ } ,
220
+ )
221
+ . with_span_suggestion (
222
+ cfg. span ,
223
+ "use `target_os` instead" ,
224
+ format ! ( "target_os = \" {platform_sym}\" " ) ,
225
+ Applicability :: MachineApplicable ,
226
+ )
227
+ . emit ( ) ;
228
+ }
229
+
230
+ PlatformVersion :: Apple { os : * platform_sym, version }
231
+ }
232
+ Err ( error) => {
233
+ sess. dcx ( ) . emit_err ( session_diagnostics:: AppleVersionInvalid {
234
+ span : * version_span,
235
+ error,
236
+ } ) ;
237
+ return false ;
238
+ }
239
+ }
240
+ }
241
+ // FIXME(madsmtm): Handle further platforms as specified in the RFC.
242
+ sym:: windows | sym:: libc => {
243
+ #[ allow( rustc:: untranslatable_diagnostic) ] // Temporary
244
+ dcx. span_err ( * platform_span, "unimplemented platform" ) ;
245
+ return false ;
246
+ }
247
+ _ => {
248
+ // Unknown platform. This is intentionally a warning (and not an error) to be
249
+ // future-compatible with later additions.
250
+ let known_platforms = [
251
+ sym:: macos,
252
+ sym:: ios,
253
+ sym:: tvos,
254
+ sym:: watchos,
255
+ sym:: visionos,
256
+ // sym::windows,
257
+ // sym::libc,
258
+ ] ;
259
+ dcx. emit_warn ( session_diagnostics:: UnknownPlatformLiteral {
260
+ span : * platform_span,
261
+ possibilities : known_platforms. into_iter ( ) . collect ( ) ,
262
+ } ) ;
263
+ return false ;
264
+ }
265
+ } ;
266
+
267
+ // Figure out actual cfg-status based on current platform.
268
+ match version {
269
+ PlatformVersion :: Apple { os, version } if os. as_str ( ) == sess. target . os => {
270
+ let deployment_target = sess. apple_deployment_target ( ) ;
271
+ version <= deployment_target
272
+ }
273
+ // If a `cfg`-value does not apply to a specific platform, assume
274
+ _ => false ,
275
+ }
276
+ }
152
277
MetaItemKind :: List ( mis) => {
153
278
for mi in mis. iter ( ) {
154
279
if mi. meta_item_or_bool ( ) . is_none ( ) {
@@ -245,3 +370,8 @@ pub fn eval_condition(
245
370
}
246
371
}
247
372
}
373
+
374
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
375
+ enum PlatformVersion {
376
+ Apple { os : Symbol , version : apple:: OSVersion } ,
377
+ }
0 commit comments