Skip to content

Commit 20998ef

Browse files
authored
Deprecate --enable-unstable and --restrict-vtable (#3859)
For unstable options, require `-Z unstable-options` instead. `--restrict-vtable` is deprecated in favor of `-Z restrict-vtable` Towards #2279 Towards #3068 ## Call-out - We should consider adding a `-Z dev-options` or something similar to distinguish between unstable features and developer only features, i.e., features not meant to be ever stabilized. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 7240545 commit 20998ef

File tree

54 files changed

+209
-108
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+209
-108
lines changed

kani-compiler/src/kani_middle/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub fn check_crate_items(tcx: TyCtxt, ignore_asm: bool) {
4444
if !ignore_asm {
4545
let error_msg = format!(
4646
"Crate {krate} contains global ASM, which is not supported by Kani. Rerun with \
47-
`--enable-unstable --ignore-global-asm` to suppress this error \
47+
`-Z unstable-options --ignore-global-asm` to suppress this error \
4848
(**Verification results may be impacted**).",
4949
);
5050
tcx.dcx().err(error_msg);

kani-driver/src/args/common.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright Kani Contributors
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33
//! Define arguments that should be common to all subcommands in Kani.
4-
use crate::args::ValidateArgs;
4+
use crate::args::{ValidateArgs, print_deprecated};
55
use clap::{error::Error, error::ErrorKind};
66
pub use kani_metadata::{EnabledUnstableFeatures, UnstableFeature};
77

@@ -43,6 +43,30 @@ impl ValidateArgs for CommonArgs {
4343
}
4444
}
4545

46+
impl CommonArgs {
47+
pub fn check_unstable(
48+
&self,
49+
enabled: bool,
50+
argument: &str,
51+
required: UnstableFeature,
52+
) -> Result<(), Error> {
53+
if enabled && !self.unstable_features.contains(required) {
54+
let z_feature = format!("-Z {required}");
55+
if self.enable_unstable {
56+
print_deprecated(self, "--enable-unstable", &z_feature);
57+
} else {
58+
return Err(Error::raw(
59+
ErrorKind::MissingRequiredArgument,
60+
format!(
61+
"The `{argument}` argument is unstable and requires `{z_feature}` to be used.",
62+
),
63+
));
64+
}
65+
}
66+
Ok(())
67+
}
68+
}
69+
4670
/// The verbosity level to be used in Kani.
4771
pub trait Verbosity {
4872
/// Whether we should be quiet.

kani-driver/src/args/mod.rs

Lines changed: 123 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ pub enum CargoKaniSubcommand {
181181
pub struct VerificationArgs {
182182
/// Temporary option to trigger assess mode for out test suite
183183
/// where we are able to add options but not subcommands
184-
#[arg(long, hide = true, requires("enable_unstable"))]
184+
#[arg(long, hide = true)]
185185
pub assess: bool,
186186

187187
/// Generate concrete playback unit test.
@@ -195,9 +195,9 @@ pub struct VerificationArgs {
195195
#[arg(long, hide_short_help = true)]
196196
pub keep_temps: bool,
197197

198-
/// Generate C file equivalent to inputted program.
199-
/// This feature is unstable and it requires `--enable-unstable` to be used
200-
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
198+
/// Generate C file equivalent to inputted program for debug purpose.
199+
/// This feature is unstable, and it requires `-Z unstable-options` to be used
200+
#[arg(long, hide_short_help = true)]
201201
pub gen_c: bool,
202202

203203
/// Directory for all generated artifacts.
@@ -247,11 +247,10 @@ pub struct VerificationArgs {
247247
#[arg(long, value_parser = CbmcSolverValueParser::new(CbmcSolver::VARIANTS))]
248248
pub solver: Option<CbmcSolver>,
249249
/// Pass through directly to CBMC; must be the last flag.
250-
/// This feature is unstable and it requires `--enable_unstable` to be used
250+
/// This feature is unstable and it requires `-Z unstable-options` to be used
251251
#[arg(
252252
long,
253253
allow_hyphen_values = true,
254-
requires("enable_unstable"),
255254
num_args(0..)
256255
)]
257256
// consumes everything
@@ -261,19 +260,19 @@ pub struct VerificationArgs {
261260
/// Omit the flag entirely to run sequentially (i.e. one thread).
262261
/// Pass -j to run with the thread pool's default number of threads.
263262
/// Pass -j <N> to specify N threads.
264-
#[arg(short, long, hide_short_help = true, requires("enable_unstable"))]
263+
#[arg(short, long, hide_short_help = true)]
265264
pub jobs: Option<Option<usize>>,
266265

267266
/// Enable extra pointer checks such as invalid pointers in relation operations and pointer
268267
/// arithmetic overflow.
269268
/// This feature is unstable and it may yield false counter examples. It requires
270-
/// `--enable-unstable` to be used
271-
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
269+
/// `-Z unstable-options` to be used
270+
#[arg(long, hide_short_help = true)]
272271
pub extra_pointer_checks: bool,
273272

274273
/// Restrict the targets of virtual table function pointer calls.
275-
/// This feature is unstable and it requires `--enable-unstable` to be used
276-
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
274+
/// This feature is unstable and it requires `-Z restrict-vtable` to be used
275+
#[arg(long, hide_short_help = true, conflicts_with = "no_restrict_vtable")]
277276
pub restrict_vtable: bool,
278277
/// Disable restricting the targets of virtual table function pointer calls
279278
#[arg(long, hide_short_help = true)]
@@ -284,26 +283,25 @@ pub struct VerificationArgs {
284283

285284
/// Do not error out for crates containing `global_asm!`.
286285
/// This option may impact the soundness of the analysis and may cause false proofs and/or counterexamples
287-
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
286+
#[arg(long, hide_short_help = true)]
288287
pub ignore_global_asm: bool,
289288

290289
/// Write the GotoC symbol table to a file in JSON format instead of goto binary format.
291290
#[arg(long, hide_short_help = true)]
292291
pub write_json_symtab: bool,
293292

294293
/// Execute CBMC's sanity checks to ensure the goto-program we generate is correct.
295-
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
294+
#[arg(long, hide_short_help = true)]
296295
pub run_sanity_checks: bool,
297296

298297
/// Disable CBMC's slice formula which prevents values from being assigned to redundant variables in traces.
299-
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
298+
#[arg(long, hide_short_help = true)]
300299
pub no_slice_formula: bool,
301300

302301
/// Synthesize loop contracts for all loops.
303302
#[arg(
304303
long,
305304
hide_short_help = true,
306-
requires("enable_unstable"),
307305
conflicts_with("unwind"),
308306
conflicts_with("default_unwind")
309307
)]
@@ -351,6 +349,8 @@ pub struct VerificationArgs {
351349
impl VerificationArgs {
352350
pub fn restrict_vtable(&self) -> bool {
353351
self.restrict_vtable
352+
|| (self.common_args.unstable_features.contains(UnstableFeature::RestrictVtable)
353+
&& !self.no_restrict_vtable)
354354
// if we flip the default, this will become: !self.no_restrict_vtable
355355
}
356356

@@ -538,16 +538,14 @@ impl ValidateArgs for CargoKaniArgs {
538538
fn validate(&self) -> Result<(), Error> {
539539
self.verify_opts.validate()?;
540540
self.command.validate()?;
541-
// --assess requires --enable-unstable, but the subcommand needs manual checking
542-
if (matches!(self.command, Some(CargoKaniSubcommand::Assess(_))) || self.verify_opts.assess)
543-
&& !self.verify_opts.common_args.enable_unstable
544-
{
545-
return Err(Error::raw(
546-
ErrorKind::MissingRequiredArgument,
547-
"Assess is unstable and requires 'cargo kani --enable-unstable assess'",
548-
));
549-
}
550-
Ok(())
541+
542+
// --assess requires -Z unstable-options, but the subcommand needs manual checking
543+
self.verify_opts.common_args.check_unstable(
544+
(matches!(self.command, Some(CargoKaniSubcommand::Assess(_)))
545+
|| self.verify_opts.assess),
546+
"assess",
547+
UnstableFeature::UnstableOptions,
548+
)
551549
}
552550
}
553551

@@ -630,20 +628,78 @@ impl ValidateArgs for VerificationArgs {
630628
}
631629
}
632630

633-
if self.concrete_playback.is_some()
634-
&& !self.common_args.unstable_features.contains(UnstableFeature::ConcretePlayback)
635-
{
636-
if self.common_args.enable_unstable {
637-
print_deprecated(&self.common_args, "--enable-unstable", "-Z concrete-playback");
638-
} else {
639-
return Err(Error::raw(
640-
ErrorKind::MissingRequiredArgument,
641-
"The `--concrete-playback` argument is unstable and requires `-Z \
642-
concrete-playback` to be used.",
643-
));
644-
}
631+
self.common_args.check_unstable(
632+
self.concrete_playback.is_some(),
633+
"--concrete-playback",
634+
UnstableFeature::ConcretePlayback,
635+
)?;
636+
637+
self.common_args.check_unstable(
638+
!self.c_lib.is_empty(),
639+
"--c-lib",
640+
UnstableFeature::CFfi,
641+
)?;
642+
643+
self.common_args.check_unstable(self.gen_c, "--gen-c", UnstableFeature::UnstableOptions)?;
644+
645+
self.common_args.check_unstable(
646+
!self.cbmc_args.is_empty(),
647+
"--cbmc-args",
648+
UnstableFeature::UnstableOptions,
649+
)?;
650+
651+
self.common_args.check_unstable(
652+
self.jobs.is_some(),
653+
"--jobs",
654+
UnstableFeature::UnstableOptions,
655+
)?;
656+
657+
self.common_args.check_unstable(
658+
self.extra_pointer_checks,
659+
"--extra-pointer-checks",
660+
UnstableFeature::UnstableOptions,
661+
)?;
662+
663+
self.common_args.check_unstable(
664+
self.ignore_global_asm,
665+
"--ignore-global-asm",
666+
UnstableFeature::UnstableOptions,
667+
)?;
668+
669+
self.common_args.check_unstable(
670+
self.run_sanity_checks,
671+
"--run-sanity-checks",
672+
UnstableFeature::UnstableOptions,
673+
)?;
674+
675+
self.common_args.check_unstable(
676+
self.no_slice_formula,
677+
"--no-slice-formula",
678+
UnstableFeature::UnstableOptions,
679+
)?;
680+
681+
self.common_args.check_unstable(
682+
self.synthesize_loop_contracts,
683+
"--synthesize-loop-contracts",
684+
UnstableFeature::UnstableOptions,
685+
)?;
686+
687+
if self.restrict_vtable {
688+
// Deprecated `--restrict-vtable` in favor our `-Z restrict-vtable`.
689+
print_deprecated(&self.common_args, "--restrict-vtable", "-Z restrict-vtable");
690+
self.common_args.check_unstable(
691+
true,
692+
"--restrict-vtable",
693+
UnstableFeature::RestrictVtable,
694+
)?;
645695
}
646696

697+
self.common_args.check_unstable(
698+
self.no_restrict_vtable,
699+
"--no-restrict-vtable",
700+
UnstableFeature::RestrictVtable,
701+
)?;
702+
647703
if !self.c_lib.is_empty()
648704
&& !self.common_args.unstable_features.contains(UnstableFeature::CFfi)
649705
{
@@ -787,7 +843,7 @@ mod tests {
787843
let a = StandaloneArgs::try_parse_from(vec![
788844
"kani",
789845
"file.rs",
790-
"--enable-unstable",
846+
"-Zunstable-options",
791847
"--cbmc-args",
792848
"--multiple",
793849
"args",
@@ -798,7 +854,7 @@ mod tests {
798854
let _b = StandaloneArgs::try_parse_from(vec![
799855
"kani",
800856
"file.rs",
801-
"--enable-unstable",
857+
"-Zunstable-options",
802858
"--cbmc-args",
803859
])
804860
.unwrap();
@@ -840,21 +896,21 @@ mod tests {
840896
assert!(b.is_ok());
841897
}
842898

843-
fn check(args: &str, require_unstable: bool, pred: fn(StandaloneArgs) -> bool) {
899+
fn check(args: &str, feature: Option<UnstableFeature>, pred: fn(StandaloneArgs) -> bool) {
844900
let mut res = parse_unstable_disabled(&args);
845-
if require_unstable {
846-
// Should fail without --enable-unstable.
901+
if let Some(unstable) = feature {
902+
// Should fail without -Z unstable-options.
847903
assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
848-
// Should succeed with --enable-unstable.
849-
res = parse_unstable_enabled(&args);
904+
// Should succeed with -Z unstable-options.
905+
res = parse_unstable_enabled(&args, unstable);
850906
}
851907
assert!(res.is_ok());
852908
assert!(pred(res.unwrap()));
853909
}
854910

855911
macro_rules! check_unstable_flag {
856912
($args:expr, $name:ident) => {
857-
check($args, true, |p| p.verify_opts.$name)
913+
check($args, Some(UnstableFeature::UnstableOptions), |p| p.verify_opts.$name)
858914
};
859915
}
860916

@@ -891,22 +947,35 @@ mod tests {
891947

892948
fn parse_unstable_disabled(args: &str) -> Result<StandaloneArgs, Error> {
893949
let args = format!("kani file.rs {args}");
894-
StandaloneArgs::try_parse_from(args.split(' '))
950+
let parse_res = StandaloneArgs::try_parse_from(args.split(' '))?;
951+
parse_res.verify_opts.validate()?;
952+
Ok(parse_res)
895953
}
896954

897-
fn parse_unstable_enabled(args: &str) -> Result<StandaloneArgs, Error> {
898-
let args = format!("kani --enable-unstable file.rs {args}");
899-
StandaloneArgs::try_parse_from(args.split(' '))
955+
fn parse_unstable_enabled(
956+
args: &str,
957+
unstable: UnstableFeature,
958+
) -> Result<StandaloneArgs, Error> {
959+
let args = format!("kani -Z {} file.rs {args}", unstable);
960+
let parse_res = StandaloneArgs::try_parse_from(args.split(' '))?;
961+
parse_res.verify_opts.validate()?;
962+
Ok(parse_res)
900963
}
901964

902965
#[test]
903966
fn check_restrict_vtable_unstable() {
904-
check_unstable_flag!("--restrict-vtable", restrict_vtable);
967+
let restrict_vtable = |args: StandaloneArgs| args.verify_opts.restrict_vtable();
968+
check("--restrict-vtable", Some(UnstableFeature::RestrictVtable), restrict_vtable);
905969
}
906970

907971
#[test]
908972
fn check_restrict_cbmc_args() {
909-
check_opt!("--cbmc-args --json-ui", true, cbmc_args, vec!["--json-ui"]);
973+
check_opt!(
974+
"--cbmc-args --json-ui",
975+
Some(UnstableFeature::UnstableOptions),
976+
cbmc_args,
977+
vec!["--json-ui"]
978+
);
910979
}
911980

912981
#[test]
@@ -938,11 +1007,11 @@ mod tests {
9381007
#[test]
9391008
fn check_concrete_playback_conflicts() {
9401009
expect_validation_error(
941-
"kani --concrete-playback=print --quiet --enable-unstable test.rs",
1010+
"kani --concrete-playback=print --quiet -Z concrete-playback test.rs",
9421011
ErrorKind::ArgumentConflict,
9431012
);
9441013
expect_validation_error(
945-
"kani --concrete-playback=inplace --output-format=old --enable-unstable test.rs",
1014+
"kani --concrete-playback=inplace --output-format=old -Z concrete-playback test.rs",
9461015
ErrorKind::ArgumentConflict,
9471016
);
9481017
}
@@ -1010,7 +1079,7 @@ mod tests {
10101079

10111080
#[test]
10121081
fn check_cbmc_args_lean_backend() {
1013-
let args = "kani input.rs -Z lean --enable-unstable --cbmc-args --object-bits 10"
1082+
let args = "kani input.rs -Z lean -Z unstable-options --cbmc-args --object-bits 10"
10141083
.split_whitespace();
10151084
let err = StandaloneArgs::try_parse_from(args).unwrap().validate().unwrap_err();
10161085
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);

kani-driver/src/assess/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn assess_project(mut session: KaniSession) -> Result<AssessMetadata> {
4949
session.codegen_tests = true;
5050
if session.args.jobs.is_none() {
5151
// assess will default to fully parallel instead of single-threaded.
52-
// can be overridden with e.g. `cargo kani --enable-unstable -j 8 assess`
52+
// can be overridden with e.g. `cargo kani -Z unstable-options -j 8 assess`
5353
session.args.jobs = Some(None); // -j, num_cpu
5454
}
5555

kani-driver/src/assess/scan.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ fn invoke_assess(
179179
// TODO: -p likewise, probably fixed with a "CargoArgs" refactoring
180180
// Additionally, this should be `--manifest-path` but `cargo kani` doesn't support that yet.
181181
cmd.arg("-p").arg(package);
182-
cmd.arg("--enable-unstable"); // This has to be after `-p` due to an argument parsing bug in kani-driver
182+
// This has to be after `-p` due to an argument parsing bug in kani-driver
183+
cmd.arg("-Zunstable-options");
183184
cmd.args(["assess", "--emit-metadata"])
184185
.arg(outfile)
185186
.current_dir(dir)

0 commit comments

Comments
 (0)