diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 577d03d1038f8..659f8f65e65d2 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -215,21 +215,29 @@ This controls which [target](targets/index.md) to produce. This flag will set which lints should be set to the [warn level](lints/levels.md#warn). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-A`: set lint allowed This flag will set which lints should be set to the [allow level](lints/levels.md#allow). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-D`: set lint denied This flag will set which lints should be set to the [deny level](lints/levels.md#deny). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-F`: set lint forbidden This flag will set which lints should be set to the [forbid level](lints/levels.md#forbid). +_Note:_ The order of these lint level arguments is taken into account, see [lint level via compiler flag](lints/levels.md#via-compiler-flag) for more information. + ## `-Z`: set unstable options diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 2944e86566313..3cfe2f698f3e0 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -164,6 +164,18 @@ And of course, you can mix these four flags together: $ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables ``` +The order of these command line arguments is taken into account. The following allows the `unused-variables` lint, because it is the last argument for that lint: + +```bash +$ rustc lib.rs --crate-type=lib -D unused-variables -A unused-variables +``` + +You can make use of this behavior by overriding the level of one specific lint out of a group of lints. The following example denies all the lints in the `unused` group, but explicitly allows the `unused-variables` lint in that group: + +```bash +$ rustc lib.rs --crate-type=lib -D unused -A unused-variables +``` + ### Via an attribute You can also modify the lint level with a crate-wide attribute: diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index b6b22e298ca62..fd4e47baad5d7 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -986,19 +986,26 @@ pub fn get_cmd_lint_options( matches: &getopts::Matches, error_format: ErrorOutputType, ) -> (Vec<(String, lint::Level)>, bool, Option) { - let mut lint_opts = vec![]; + let mut lint_opts_with_position = vec![]; let mut describe_lints = false; for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { - for lint_name in matches.opt_strs(level.as_str()) { + for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) { if lint_name == "help" { describe_lints = true; } else { - lint_opts.push((lint_name.replace("-", "_"), level)); + lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level)); } } } + lint_opts_with_position.sort_by_key(|x| x.0); + let lint_opts = lint_opts_with_position + .iter() + .cloned() + .map(|(_, lint_name, level)| (lint_name, level)) + .collect(); + let lint_cap = matches.opt_str("cap-lints").map(|cap| { lint::Level::from_str(&cap) .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap))) diff --git a/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs b/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs new file mode 100644 index 0000000000000..7498745f20699 --- /dev/null +++ b/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs @@ -0,0 +1,7 @@ +// aux-build:lint-group-plugin-test.rs +// check-pass +// compile-flags: -D unused -A unused-variables + +fn main() { + let x = 1; +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 226a12c6734b7..84bae6cd27edd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1478,11 +1478,7 @@ impl<'test> TestCx<'test> { WillExecute::No => TargetLocation::ThisDirectory(self.output_base_dir()), }; - let mut rustc = self.make_compile_args(&self.testpaths.file, output_file, emit_metadata); - - rustc.arg("-L").arg(&self.aux_output_dir_name()); - - match self.config.mode { + let allow_unused = match self.config.mode { CompileFail | Ui => { // compile-fail and ui tests tend to have tons of unused code as // it's just testing various pieces of the compile, but we don't @@ -1495,11 +1491,18 @@ impl<'test> TestCx<'test> { // via command line flags. && local_pm != Some(PassMode::Run) { - rustc.args(&["-A", "unused"]); + AllowUnused::Yes + } else { + AllowUnused::No } } - _ => {} - } + _ => AllowUnused::No, + }; + + let mut rustc = + self.make_compile_args(&self.testpaths.file, output_file, emit_metadata, allow_unused); + + rustc.arg("-L").arg(&self.aux_output_dir_name()); self.compose_and_run_compiler(rustc, None) } @@ -1710,7 +1713,8 @@ impl<'test> TestCx<'test> { // Create the directory for the stdout/stderr files. create_dir_all(aux_cx.output_base_dir()).unwrap(); let input_file = &aux_testpaths.file; - let mut aux_rustc = aux_cx.make_compile_args(input_file, aux_output, EmitMetadata::No); + let mut aux_rustc = + aux_cx.make_compile_args(input_file, aux_output, EmitMetadata::No, AllowUnused::No); let (dylib, crate_type) = if aux_props.no_prefer_dynamic { (true, None) @@ -1819,6 +1823,7 @@ impl<'test> TestCx<'test> { input_file: &Path, output_file: TargetLocation, emit_metadata: EmitMetadata, + allow_unused: AllowUnused, ) -> Command { let is_rustdoc = self.is_rustdoc(); let mut rustc = if !is_rustdoc { @@ -1951,6 +1956,10 @@ impl<'test> TestCx<'test> { rustc.arg("-Ctarget-feature=-crt-static"); } + if let AllowUnused::Yes = allow_unused { + rustc.args(&["-A", "unused"]); + } + rustc.args(&self.props.compile_flags); rustc @@ -2134,7 +2143,8 @@ impl<'test> TestCx<'test> { let output_file = TargetLocation::ThisDirectory(self.output_base_dir()); let input_file = &self.testpaths.file; - let mut rustc = self.make_compile_args(input_file, output_file, EmitMetadata::No); + let mut rustc = + self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No); rustc.arg("-L").arg(aux_dir).arg("--emit=llvm-ir"); self.compose_and_run_compiler(rustc, None) @@ -2147,7 +2157,8 @@ impl<'test> TestCx<'test> { let output_file = TargetLocation::ThisFile(output_path.clone()); let input_file = &self.testpaths.file; - let mut rustc = self.make_compile_args(input_file, output_file, EmitMetadata::No); + let mut rustc = + self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No); rustc.arg("-L").arg(self.aux_output_dir_name()); @@ -2999,6 +3010,7 @@ impl<'test> TestCx<'test> { &self.testpaths.file.with_extension(UI_FIXED), TargetLocation::ThisFile(self.make_exe_name()), emit_metadata, + AllowUnused::No, ); rustc.arg("-L").arg(&self.aux_output_dir_name()); let res = self.compose_and_run_compiler(rustc, None); @@ -3486,6 +3498,11 @@ enum ExpectedLine> { Text(T), } +enum AllowUnused { + Yes, + No, +} + impl fmt::Debug for ExpectedLine where T: AsRef + fmt::Debug,