diff options
| author | bors <bors@rust-lang.org> | 2024-08-07 17:32:16 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-08-07 17:32:16 +0000 |
| commit | ce20e15f01a9dcc4543e8d52b4b281df6c4dbb8e (patch) | |
| tree | 24772ddefecdbaa62e3c84c31b984c35d5b7e6de /compiler | |
| parent | 8d0066922b14cee3175e8c141e5e909fa6d9a6eb (diff) | |
| parent | c0c57b3e2953241124810a59faf77d50e91b3e01 (diff) | |
| download | rust-ce20e15f01a9dcc4543e8d52b4b281df6c4dbb8e.tar.gz rust-ce20e15f01a9dcc4543e8d52b4b281df6c4dbb8e.zip | |
Auto merge of #126158 - Urgau:disallow-cfgs, r=petrochenkov
Disallow setting some built-in cfg via set the command-line
This PR disallow users from setting some built-in cfg via set the command-line in order to prevent incoherent state, eg. `windows` cfg active but target is Linux based.
This implements MCP https://github.com/rust-lang/compiler-team/issues/610, with the caveat that we disallow cfgs no matter if they make sense or not, since I don't think it's useful to allow users to set a cfg that will be set anyway. It also complicates the implementation.
------
The `explicit_builtin_cfgs_in_flags` lint detects builtin cfgs set via the `--cfg` flag.
*(deny-by-default)*
### Example
```text
rustc --cfg unix
```
```rust,ignore (needs command line option)
fn main() {}
```
This will produce:
```text
error: unexpected `--cfg unix` flag
|
= note: config `unix` is only supposed to be controlled by `--target`
= note: manually setting a built-in cfg can and does create incoherent behaviours
= note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
```
### Explanation
Setting builtin cfgs can and does produce incoherent behaviour, it's better to the use the appropriate `rustc` flag that controls the config. For example setting the `windows` cfg but on Linux based target.
-----
r? `@petrochenkov`
cc `@jyn514`
try-job: aarch64-apple
try-job: test-various
try-job: armhf-gnu
try-job: x86_64-msvc
try-job: x86_64-mingw
try-job: i686-msvc
try-job: i686-mingw
try-job: x86_64-gnu-llvm-17
try-job: dist-various-1
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_builtin_macros/src/format.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_lint/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/context.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/context/diagnostics.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/early.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lints.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_lint_defs/src/builtin.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_lint_defs/src/lib.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_session/src/config.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_session/src/config/cfg.rs | 65 | ||||
| -rw-r--r-- | compiler/rustc_session/src/parse.rs | 12 |
11 files changed, 156 insertions, 8 deletions
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 9c70f7ede8c..ff82f0f2da7 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -555,7 +555,7 @@ fn make_format_args( }; let arg_name = args.explicit_args()[index].kind.ident().unwrap(); ecx.buffered_early_lint.push(BufferedEarlyLint { - span: arg_name.span.into(), + span: Some(arg_name.span.into()), node_id: rustc_ast::CRATE_NODE_ID, lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY), diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d0be6cbee6e..7a394a6d6c1 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -775,6 +775,10 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value +lint_unexpected_builtin_cfg = unexpected `--cfg {$cfg}` flag + .controlled_by = config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}` + .incoherent = manually setting a built-in cfg can and does create incoherent behaviors + lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs` lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 11ad1aa0e8d..c9e2eee16b3 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -533,7 +533,7 @@ pub struct EarlyContext<'a> { } impl EarlyContext<'_> { - /// Emit a lint at the appropriate level, with an optional associated span and an existing + /// Emit a lint at the appropriate level, with an associated span and an existing /// diagnostic. /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature @@ -544,7 +544,21 @@ impl EarlyContext<'_> { span: MultiSpan, diagnostic: BuiltinLintDiag, ) { - self.opt_span_lint(lint, Some(span), |diag| { + self.opt_span_lint_with_diagnostics(lint, Some(span), diagnostic); + } + + /// Emit a lint at the appropriate level, with an optional associated span and an existing + /// diagnostic. + /// + /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature + #[rustc_lint_diagnostics] + pub fn opt_span_lint_with_diagnostics( + &self, + lint: &'static Lint, + span: Option<MultiSpan>, + diagnostic: BuiltinLintDiag, + ) { + self.opt_span_lint(lint, span, |diag| { diagnostics::decorate_lint(self.sess(), diagnostic, diag); }); } diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index a96af076477..f289d4c81b3 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -438,5 +438,8 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::OutOfScopeMacroCalls { path } => { lints::OutOfScopeMacroCalls { path }.decorate_lint(diag) } + BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => { + lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag) + } } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 7b04e8c39e6..6fb0a624644 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -47,7 +47,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { fn inlined_check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; - self.context.span_lint_with_diagnostics(lint_id.lint, span, diagnostic); + self.context.opt_span_lint_with_diagnostics(lint_id.lint, span, diagnostic); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1a657d31865..03962d796f4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2380,6 +2380,16 @@ pub mod unexpected_cfg_value { } #[derive(LintDiagnostic)] +#[diag(lint_unexpected_builtin_cfg)] +#[note(lint_controlled_by)] +#[note(lint_incoherent)] +pub struct UnexpectedBuiltinCfg { + pub(crate) cfg: String, + pub(crate) cfg_name: Symbol, + pub(crate) controlled_by: &'static str, +} + +#[derive(LintDiagnostic)] #[diag(lint_macro_use_deprecated)] #[help] pub struct MacroUseDeprecated; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ff0bdfcc9d2..c731b03a875 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -42,6 +42,7 @@ declare_lint_pass! { DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, ELIDED_LIFETIMES_IN_PATHS, + EXPLICIT_BUILTIN_CFGS_IN_FLAGS, EXPORTED_PRIVATE_DEPENDENCIES, FFI_UNWIND_CALLS, FORBIDDEN_LINT_GROUPS, @@ -3289,6 +3290,39 @@ declare_lint! { } declare_lint! { + /// The `explicit_builtin_cfgs_in_flags` lint detects builtin cfgs set via the `--cfg` flag. + /// + /// ### Example + /// + /// ```text + /// rustc --cfg unix + /// ``` + /// + /// ```rust,ignore (needs command line option) + /// fn main() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: unexpected `--cfg unix` flag + /// | + /// = note: config `unix` is only supposed to be controlled by `--target` + /// = note: manually setting a built-in cfg can and does create incoherent behaviors + /// = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// Setting builtin cfgs can and does produce incoherent behavior, it's better to the use + /// the appropriate `rustc` flag that controls the config. For example setting the `windows` + /// cfg but on Linux based target. + pub EXPLICIT_BUILTIN_CFGS_IN_FLAGS, + Deny, + "detects builtin cfgs set via the `--cfg`" +} + +declare_lint! { /// The `repr_transparent_external_private_fields` lint /// detects types marked `#[repr(transparent)]` that (transitively) /// contain an external ZST type marked `#[non_exhaustive]` or containing diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 19efa36b40f..0f07de43e80 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -746,6 +746,11 @@ pub enum BuiltinLintDiag { OutOfScopeMacroCalls { path: String, }, + UnexpectedBuiltinCfg { + cfg: String, + cfg_name: Symbol, + controlled_by: &'static str, + }, } /// Lints that are buffered up early on in the `Session` before the @@ -753,7 +758,7 @@ pub enum BuiltinLintDiag { #[derive(Debug)] pub struct BufferedEarlyLint { /// The span of code that we are linting on. - pub span: MultiSpan, + pub span: Option<MultiSpan>, /// The `NodeId` of the AST node that generated the lint. pub node_id: NodeId, @@ -791,7 +796,7 @@ impl LintBuffer { self.add_early_lint(BufferedEarlyLint { lint_id: LintId::of(lint), node_id, - span: span.into(), + span: Some(span.into()), diagnostic, }); } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a60af3f2d71..20c14a98502 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1304,7 +1304,10 @@ pub(crate) const fn default_lib_output() -> CrateType { } pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { - // Combine the configuration requested by the session (command line) with + // First disallow some configuration given on the command line + cfg::disallow_cfgs(sess, &user_cfg); + + // Then combine the configuration requested by the session (command line) with // some default and generated configuration items. user_cfg.extend(cfg::default_configuration(sess)); user_cfg diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 4109ebb6d34..a64b1e21e9e 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -17,12 +17,16 @@ //! - Add the activation logic in [`default_configuration`] //! - Add the cfg to [`CheckCfg::fill_well_known`] (and related files), //! so that the compiler can know the cfg is expected +//! - Add the cfg in [`disallow_cfgs`] to disallow users from setting it via `--cfg` //! - Add the feature gating in `compiler/rustc_feature/src/builtin_attrs.rs` use std::hash::Hash; use std::iter; +use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS; +use rustc_lint_defs::BuiltinLintDiag; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Align; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, Target, TargetTriple, TARGETS}; @@ -82,6 +86,67 @@ impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> { } } +/// Disallow builtin cfgs from the CLI. +pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { + let disallow = |cfg: &(Symbol, Option<Symbol>), controlled_by| { + let cfg_name = cfg.0; + let cfg = if let Some(value) = cfg.1 { + format!(r#"{}="{}""#, cfg_name, value) + } else { + format!("{}", cfg_name) + }; + sess.psess.opt_span_buffer_lint( + EXPLICIT_BUILTIN_CFGS_IN_FLAGS, + None, + ast::CRATE_NODE_ID, + BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }, + ) + }; + + // We want to restrict setting builtin cfgs that will produce incoherent behavior + // between the cfg and the rustc cli flag that sets it. + // + // The tests are in tests/ui/cfg/disallowed-cli-cfgs.rs. + + // By-default all builtin cfgs are disallowed, only those are allowed: + // - test: as it makes sense to the have the `test` cfg active without the builtin + // test harness. See Cargo `harness = false` config. + // + // Cargo `--cfg test`: https://github.com/rust-lang/cargo/blob/bc89bffa5987d4af8f71011c7557119b39e44a65/src/cargo/core/compiler/mod.rs#L1124 + + for cfg in user_cfgs { + match cfg { + (sym::overflow_checks, None) => disallow(cfg, "-C overflow-checks"), + (sym::debug_assertions, None) => disallow(cfg, "-C debug-assertions"), + (sym::ub_checks, None) => disallow(cfg, "-Z ub-checks"), + (sym::sanitize, None | Some(_)) => disallow(cfg, "-Z sanitizer"), + ( + sym::sanitizer_cfi_generalize_pointers | sym::sanitizer_cfi_normalize_integers, + None | Some(_), + ) => disallow(cfg, "-Z sanitizer=cfi"), + (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"), + (sym::panic, Some(sym::abort | sym::unwind)) => disallow(cfg, "-C panic"), + (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"), + (sym::unix, None) + | (sym::windows, None) + | (sym::relocation_model, Some(_)) + | (sym::target_abi, None | Some(_)) + | (sym::target_arch, Some(_)) + | (sym::target_endian, Some(_)) + | (sym::target_env, None | Some(_)) + | (sym::target_family, Some(_)) + | (sym::target_os, Some(_)) + | (sym::target_pointer_width, Some(_)) + | (sym::target_vendor, None | Some(_)) + | (sym::target_has_atomic, Some(_)) + | (sym::target_has_atomic_equal_alignment, Some(_)) + | (sym::target_has_atomic_load_store, Some(_)) + | (sym::target_thread_local, None) => disallow(cfg, "--target"), + _ => {} + } + } +} + /// Generate the default configs for a given session pub(crate) fn default_configuration(sess: &Session) -> Cfg { let mut ret = Cfg::default(); diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index ebd5021dae1..d6c58e9d1be 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -307,9 +307,19 @@ impl ParseSess { node_id: NodeId, diagnostic: BuiltinLintDiag, ) { + self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic) + } + + pub fn opt_span_buffer_lint( + &self, + lint: &'static Lint, + span: Option<MultiSpan>, + node_id: NodeId, + diagnostic: BuiltinLintDiag, + ) { self.buffered_lints.with_lock(|buffered_lints| { buffered_lints.push(BufferedEarlyLint { - span: span.into(), + span, node_id, lint_id: LintId::of(lint), diagnostic, |
