Skip to content

Commit 6125af0

Browse files
committed
Add cfg_os_version_min feature
Based on in-progress RFC: rust-lang/rfcs#3750. Only implemented for Apple platforms for now, but written in a way that should be easily expandable to include other platforms.
1 parent 1b9ec41 commit 6125af0

16 files changed

+558
-2
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3460,6 +3460,7 @@ dependencies = [
34603460
"rustc_serialize",
34613461
"rustc_session",
34623462
"rustc_span",
3463+
"rustc_target",
34633464
]
34643465

34653466
[[package]]

compiler/rustc_attr_parsing/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ rustc_macros = { path = "../rustc_macros" }
1818
rustc_serialize = { path = "../rustc_serialize" }
1919
rustc_session = { path = "../rustc_session" }
2020
rustc_span = { path = "../rustc_span" }
21+
rustc_target = { path = "../rustc_target" }
2122
# tidy-alphabetical-end

compiler/rustc_attr_parsing/messages.ftl

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
attr_parsing_apple_version_invalid =
2+
failed parsing version: {$error}
3+
4+
attr_parsing_apple_version_unnecessarily_low =
5+
version is set unnecessarily low, the minimum supported by Rust on this platform is {$os_min}
6+
17
attr_parsing_cfg_predicate_identifier =
28
`cfg` predicate key must be an identifier
39
@@ -9,6 +15,12 @@ attr_parsing_deprecated_item_suggestion =
915
attr_parsing_expected_one_cfg_pattern =
1016
expected 1 cfg-pattern
1117
18+
attr_parsing_expected_platform_and_version_literals =
19+
expected two literals, a platform and a version
20+
21+
attr_parsing_expected_platform_literal =
22+
expected a platform literal
23+
1224
attr_parsing_expected_single_version_literal =
1325
expected single version literal
1426
@@ -104,6 +116,9 @@ attr_parsing_unknown_meta_item =
104116
unknown meta item '{$item}'
105117
.label = expected one of {$expected}
106118
119+
attr_parsing_unknown_platform_literal =
120+
unknown platform literal, expected values are: {$possibilities}
121+
107122
attr_parsing_unknown_version_literal =
108123
unknown version literal format, assuming it refers to a future version
109124

compiler/rustc_attr_parsing/src/attributes/cfg.rs

+122
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_session::lint::BuiltinLintDiag;
1010
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
1111
use rustc_session::parse::feature_err;
1212
use rustc_span::{Span, Symbol, kw, sym};
13+
use rustc_target::spec::apple;
1314

1415
use crate::util::UnsupportedLiteralReason;
1516
use 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+
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
1-
use std::num::IntErrorKind;
1+
use std::num::{IntErrorKind, ParseIntError};
22

33
use rustc_ast as ast;
44
use rustc_errors::codes::*;
5-
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
5+
use rustc_errors::{
6+
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
7+
};
68
use rustc_macros::{Diagnostic, Subdiagnostic};
79
use rustc_span::{Span, Symbol};
810

911
use crate::attributes::util::UnsupportedLiteralReason;
1012
use crate::fluent_generated as fluent;
1113

14+
#[derive(Diagnostic)]
15+
#[diag(attr_parsing_apple_version_invalid)]
16+
pub(crate) struct AppleVersionInvalid {
17+
#[primary_span]
18+
pub span: Span,
19+
pub error: ParseIntError,
20+
}
21+
22+
#[derive(Diagnostic)]
23+
#[diag(attr_parsing_apple_version_unnecessarily_low)]
24+
pub(crate) struct AppleVersionUnnecessarilyLow {
25+
#[primary_span]
26+
pub span: Span,
27+
pub os_min: String,
28+
}
29+
1230
#[derive(Diagnostic)]
1331
#[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)]
1432
pub(crate) struct ExpectedOneCfgPattern {
@@ -371,6 +389,20 @@ pub(crate) struct DeprecatedItemSuggestion {
371389
pub details: (),
372390
}
373391

392+
#[derive(Diagnostic)]
393+
#[diag(attr_parsing_expected_platform_and_version_literals)]
394+
pub(crate) struct ExpectedPlatformAndVersionLiterals {
395+
#[primary_span]
396+
pub span: Span,
397+
}
398+
399+
#[derive(Diagnostic)]
400+
#[diag(attr_parsing_expected_platform_literal)]
401+
pub(crate) struct ExpectedPlatformLiteral {
402+
#[primary_span]
403+
pub span: Span,
404+
}
405+
374406
#[derive(Diagnostic)]
375407
#[diag(attr_parsing_expected_single_version_literal)]
376408
pub(crate) struct ExpectedSingleVersionLiteral {
@@ -417,6 +449,14 @@ pub(crate) struct SoftNoArgs {
417449
pub span: Span,
418450
}
419451

452+
#[derive(Diagnostic)]
453+
#[diag(attr_parsing_unknown_platform_literal)]
454+
pub(crate) struct UnknownPlatformLiteral {
455+
#[primary_span]
456+
pub span: Span,
457+
pub possibilities: DiagSymbolList,
458+
}
459+
420460
#[derive(Diagnostic)]
421461
#[diag(attr_parsing_unknown_version_literal)]
422462
pub(crate) struct UnknownVersionLiteral {

compiler/rustc_feature/src/builtin_attrs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const GATED_CFGS: &[GatedCfg] = &[
3333
),
3434
(sym::sanitize, sym::cfg_sanitize, Features::cfg_sanitize),
3535
(sym::version, sym::cfg_version, Features::cfg_version),
36+
(sym::os_version_min, sym::cfg_os_version_min, Features::cfg_os_version_min),
3637
(sym::relocation_model, sym::cfg_relocation_model, Features::cfg_relocation_model),
3738
(sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
3839
(sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ declare_features! (
405405
(unstable, cfg_boolean_literals, "1.83.0", Some(131204)),
406406
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
407407
(unstable, cfg_contract_checks, "CURRENT_RUSTC_VERSION", Some(128044)),
408+
/// Allow conditional compilation depending on target platform version.
409+
(unstable, cfg_os_version_min, "CURRENT_RUSTC_VERSION", Some(136866)),
408410
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
409411
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
410412
/// Provides the relocation model information as cfg entry

compiler/rustc_span/src/symbol.rs

+7
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ symbols! {
577577
cfg_eval,
578578
cfg_fmt_debug,
579579
cfg_hide,
580+
cfg_os_version_min,
580581
cfg_overflow_checks,
581582
cfg_panic,
582583
cfg_relocation_model,
@@ -1139,6 +1140,7 @@ symbols! {
11391140
intrinsics_unaligned_volatile_store,
11401141
io_stderr,
11411142
io_stdout,
1143+
ios,
11421144
irrefutable_let_patterns,
11431145
is,
11441146
is_val_statically_known,
@@ -1224,6 +1226,7 @@ symbols! {
12241226
loop_break_value,
12251227
lt,
12261228
m68k_target_feature,
1229+
macos,
12271230
macro_at_most_once_rep,
12281231
macro_attributes_in_derive_output,
12291232
macro_escape,
@@ -1449,6 +1452,7 @@ symbols! {
14491452
ord_cmp_method,
14501453
os_str_to_os_string,
14511454
os_string_as_os_str,
1455+
os_version_min,
14521456
other,
14531457
out,
14541458
overflow_checks,
@@ -2064,6 +2068,7 @@ symbols! {
20642068
tuple,
20652069
tuple_indexing,
20662070
tuple_trait,
2071+
tvos,
20672072
two_phase,
20682073
ty,
20692074
type_alias_enum_variants,
@@ -2206,6 +2211,7 @@ symbols! {
22062211
vfp2,
22072212
vis,
22082213
visible_private_types,
2214+
visionos,
22092215
volatile,
22102216
volatile_copy_memory,
22112217
volatile_copy_nonoverlapping_memory,
@@ -2222,6 +2228,7 @@ symbols! {
22222228
wasm_abi,
22232229
wasm_import_module,
22242230
wasm_target_feature,
2231+
watchos,
22252232
while_let,
22262233
windows,
22272234
windows_subsystem,

0 commit comments

Comments
 (0)