]> git.proxmox.com Git - cargo.git/commitdiff
Stabilize namespaced and weak dependency features.
authorEric Huss <eric@huss.org>
Thu, 6 Jan 2022 23:46:15 +0000 (15:46 -0800)
committerEric Huss <eric@huss.org>
Thu, 6 Jan 2022 23:56:56 +0000 (15:56 -0800)
19 files changed:
Cargo.toml
crates/crates-io/Cargo.toml
crates/crates-io/lib.rs
src/bin/cargo/commands/read_manifest.rs
src/cargo/core/features.rs
src/cargo/core/package.rs
src/cargo/core/resolver/features.rs
src/cargo/core/summary.rs
src/cargo/ops/cargo_output_metadata.rs
src/cargo/ops/registry.rs
src/cargo/sources/registry/index.rs
src/cargo/util/toml/mod.rs
src/doc/src/reference/features.md
src/doc/src/reference/registries.md
src/doc/src/reference/unstable.md
tests/testsuite/features.rs
tests/testsuite/features_namespaced.rs
tests/testsuite/old_cargos.rs
tests/testsuite/weak_dep_features.rs

index 20dfd540f0bcfa13b4008532c0dd7ddee43057e2..0f9dcc1b1d9b2f487be1cd6a3c9d69602be0b21e 100644 (file)
@@ -20,7 +20,7 @@ atty = "0.2"
 bytesize = "1.0"
 cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" }
 cargo-util = { path = "crates/cargo-util", version = "0.1.2" }
-crates-io = { path = "crates/crates-io", version = "0.33.1" }
+crates-io = { path = "crates/crates-io", version = "0.34.0" }
 crossbeam-utils = "0.8"
 curl = { version = "0.4.41", features = ["http2"] }
 curl-sys = "0.4.50"
index 025f8e8ebc69a62368437a6f685c61a7436b1959..777bdfac9eb165136dc3ad14fe665d1611fd267d 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "crates-io"
-version = "0.33.1"
+version = "0.34.0"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/cargo"
index f7ed67382d48ec06043608f6e923cd221ac03a27..bbc12893e810e9e8b8b328166f28c84877857049 100644 (file)
@@ -55,8 +55,6 @@ pub struct NewCrate {
     pub repository: Option<String>,
     pub badges: BTreeMap<String, BTreeMap<String, String>>,
     pub links: Option<String>,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub v: Option<u32>,
 }
 
 #[derive(Serialize)]
index 86867152c93bf218dafc44d0836eef1126e149ca..d6a7bccbbdb9e814901e778a2abe89e321618a0f 100644 (file)
@@ -15,8 +15,6 @@ Deprecated, use `cargo metadata --no-deps` instead.\
 
 pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
     let ws = args.workspace(config)?;
-    config
-        .shell()
-        .print_json(&ws.current()?.serialized(config))?;
+    config.shell().print_json(&ws.current()?.serialized())?;
     Ok(())
 }
index 968290a380e2ad2b0c097653ea47ecaa8dc310b8..8be29b9b748401c60f9909b239abb6801126925a 100644 (file)
@@ -642,7 +642,6 @@ unstable_cli_options!(
     minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
     mtime_on_use: bool = ("Configure Cargo to update the mtime of used files"),
     multitarget: bool = ("Allow passing multiple `--target` flags to the cargo subcommand selected"),
-    namespaced_features: bool = ("Allow features with `dep:` prefix"),
     no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
     panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
     host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
@@ -652,7 +651,6 @@ unstable_cli_options!(
     terminal_width: Option<Option<usize>>  = ("Provide a terminal width to rustc for error truncation"),
     timings: Option<Vec<String>>  = ("Display concurrency information"),
     unstable_options: bool = ("Allow the usage of unstable options"),
-    weak_dep_features: bool = ("Allow `dep_name?/feature` feature syntax"),
     // TODO(wcrichto): move scrape example configuration into Cargo.toml before stabilization
     // See: https://github.com/rust-lang/cargo/pull/9525#discussion_r728470927
     rustdoc_scrape_examples: Option<String> = ("Allow rustdoc to scrape examples from reverse-dependencies for documentation"),
@@ -707,6 +705,10 @@ const STABILIZED_NAMED_PROFILES: &str = "The named-profiles feature is now alway
 const STABILIZED_FUTURE_INCOMPAT_REPORT: &str =
     "The future-incompat-report feature is now always enabled.";
 
+const STABILIZED_WEAK_DEP_FEATURES: &str = "Weak dependency features are now always available.";
+
+const STABILISED_NAMESPACED_FEATURES: &str = "Namespaced features are now always available.";
+
 fn deserialize_build_std<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
 where
     D: serde::Deserializer<'de>,
@@ -873,8 +875,8 @@ impl CliUnstable {
             "multitarget" => self.multitarget = parse_empty(k, v)?,
             "rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
             "terminal-width" => self.terminal_width = Some(parse_usize_opt(v)?),
-            "namespaced-features" => self.namespaced_features = parse_empty(k, v)?,
-            "weak-dep-features" => self.weak_dep_features = parse_empty(k, v)?,
+            "namespaced-features" => stabilized_warn(k, "1.60", STABILISED_NAMESPACED_FEATURES),
+            "weak-dep-features" => stabilized_warn(k, "1.60", STABILIZED_WEAK_DEP_FEATURES),
             "credential-process" => self.credential_process = parse_empty(k, v)?,
             "rustdoc-scrape-examples" => {
                 if let Some(s) = v {
index dd73ea25c24349d2e4e9a9c6352c44565afe1b93..c447610f2c9ff6ddd18bd25ffe03281ab239f46b 100644 (file)
@@ -208,7 +208,7 @@ impl Package {
         self.targets().iter().any(|t| t.is_example() || t.is_bin())
     }
 
-    pub fn serialized(&self, config: &Config) -> SerializedPackage {
+    pub fn serialized(&self) -> SerializedPackage {
         let summary = self.manifest().summary();
         let package_id = summary.package_id();
         let manmeta = self.manifest().metadata();
@@ -222,27 +222,19 @@ impl Package {
             .filter(|t| t.src_path().is_path())
             .cloned()
             .collect();
-        let features = if config.cli_unstable().namespaced_features {
-            // Convert Vec<FeatureValue> to Vec<InternedString>
-            summary
-                .features()
-                .iter()
-                .map(|(k, v)| {
-                    (
-                        *k,
-                        v.iter()
-                            .map(|fv| InternedString::new(&fv.to_string()))
-                            .collect(),
-                    )
-                })
-                .collect()
-        } else {
-            self.manifest()
-                .original()
-                .features()
-                .cloned()
-                .unwrap_or_default()
-        };
+        // Convert Vec<FeatureValue> to Vec<InternedString>
+        let features = summary
+            .features()
+            .iter()
+            .map(|(k, v)| {
+                (
+                    *k,
+                    v.iter()
+                        .map(|fv| InternedString::new(&fv.to_string()))
+                        .collect(),
+                )
+            })
+            .collect();
 
         SerializedPackage {
             name: package_id.name(),
index 31b6c783374db35be9d29dba441d5bdb4a80ed44..1c1ef451ecb90147cf328e465a1fe1198dc40160 100644 (file)
@@ -1,19 +1,14 @@
 //! Feature resolver.
 //!
 //! This is a new feature resolver that runs independently of the main
-//! dependency resolver. It is enabled when the user specifies `resolver =
-//! "2"` in `Cargo.toml`.
+//! dependency resolver. It has several options which can enable new feature
+//! resolution behavior.
 //!
 //! One of its key characteristics is that it can avoid unifying features for
 //! shared dependencies in some situations. See `FeatureOpts` for the
 //! different behaviors that can be enabled. If no extra options are enabled,
 //! then it should behave exactly the same as the dependency resolver's
-//! feature resolution. This can be verified by setting the
-//! `__CARGO_FORCE_NEW_FEATURES=compare` environment variable and running
-//! Cargo's test suite (or building other projects), and checking if it
-//! panics. Note: the `features2` tests will fail because they intentionally
-//! compare the old vs new behavior, so forcing the old behavior will
-//! naturally fail the tests.
+//! feature resolution.
 //!
 //! The preferred way to engage this new resolver is via
 //! `resolve_ws_with_opts`.
@@ -59,22 +54,12 @@ pub struct ResolvedFeatures {
     ///
     /// The value is the `name_in_toml` of the dependencies.
     activated_dependencies: ActivateMap,
-    /// This is only here for legacy support when the new resolver is not enabled.
-    ///
-    /// This is the set of features enabled for each package.
-    legacy_features: Option<HashMap<PackageId, Vec<InternedString>>>,
-    /// This is only here for legacy support when the new resolver is not enabled.
-    ///
-    /// This is the set of optional dependencies enabled for each package.
-    legacy_dependencies: Option<HashMap<PackageId, HashSet<InternedString>>>,
     opts: FeatureOpts,
 }
 
 /// Options for how the feature resolver works.
 #[derive(Default)]
 pub struct FeatureOpts {
-    /// Use the new resolver instead of the old one.
-    new_resolver: bool,
     /// Build deps and proc-macros will not share share features with other dep kinds.
     decouple_host_deps: bool,
     /// Dev dep features will not be activated unless needed.
@@ -132,7 +117,6 @@ impl FeatureOpts {
         let mut opts = FeatureOpts::default();
         let unstable_flags = ws.config().cli_unstable();
         let mut enable = |feat_opts: &Vec<String>| {
-            opts.new_resolver = true;
             for opt in feat_opts {
                 match opt.as_ref() {
                     "build_dep" | "host_dep" => opts.decouple_host_deps = true,
@@ -159,15 +143,6 @@ impl FeatureOpts {
                 enable(&vec!["all".to_string()]).unwrap();
             }
         }
-        // This env var is intended for testing only.
-        if let Ok(env_opts) = std::env::var("__CARGO_FORCE_NEW_FEATURES") {
-            if env_opts == "1" {
-                opts.new_resolver = true;
-            } else {
-                let env_opts = env_opts.split(',').map(|s| s.to_string()).collect();
-                enable(&env_opts)?;
-            }
-        }
         if let HasDevUnits::Yes = has_dev_units {
             // Dev deps cannot be decoupled when they are in use.
             opts.decouple_dev_deps = false;
@@ -175,10 +150,6 @@ impl FeatureOpts {
         if let ForceAllTargets::Yes = force_all_targets {
             opts.ignore_inactive_targets = false;
         }
-        if unstable_flags.weak_dep_features {
-            // Force this ON because it only works with the new resolver.
-            opts.new_resolver = true;
-        }
         Ok(opts)
     }
 
@@ -187,7 +158,6 @@ impl FeatureOpts {
         match behavior {
             ResolveBehavior::V1 => FeatureOpts::default(),
             ResolveBehavior::V2 => FeatureOpts {
-                new_resolver: true,
                 decouple_host_deps: true,
                 decouple_dev_deps: has_dev_units == HasDevUnits::No,
                 ignore_inactive_targets: true,
@@ -306,18 +276,11 @@ impl ResolvedFeatures {
         features_for: FeaturesFor,
         dep_name: InternedString,
     ) -> bool {
-        if let Some(legacy) = &self.legacy_dependencies {
-            legacy
-                .get(&pkg_id)
-                .map(|deps| deps.contains(&dep_name))
-                .unwrap_or(false)
-        } else {
-            let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
-            self.activated_dependencies
-                .get(&(pkg_id, is_build))
-                .map(|deps| deps.contains(&dep_name))
-                .unwrap_or(false)
-        }
+        let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
+        self.activated_dependencies
+            .get(&(pkg_id, is_build))
+            .map(|deps| deps.contains(&dep_name))
+            .unwrap_or(false)
     }
 
     /// Variant of `activated_features` that returns `None` if this is
@@ -336,15 +299,11 @@ impl ResolvedFeatures {
         pkg_id: PackageId,
         features_for: FeaturesFor,
     ) -> CargoResult<Vec<InternedString>> {
-        if let Some(legacy) = &self.legacy_features {
-            Ok(legacy.get(&pkg_id).map_or_else(Vec::new, |v| v.clone()))
+        let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
+        if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
+            Ok(fs.iter().cloned().collect())
         } else {
-            let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
-            if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
-                Ok(fs.iter().cloned().collect())
-            } else {
-                bail!("features did not find {:?} {:?}", pkg_id, is_build)
-            }
+            bail!("features did not find {:?} {:?}", pkg_id, is_build)
         }
     }
 
@@ -352,14 +311,16 @@ impl ResolvedFeatures {
     ///
     /// Used by `cargo fix --edition` to display any differences.
     pub fn compare_legacy(&self, legacy: &ResolvedFeatures) -> DiffMap {
-        let legacy_features = legacy.legacy_features.as_ref().unwrap();
         self.activated_features
             .iter()
             .filter_map(|((pkg_id, for_host), new_features)| {
-                let old_features = match legacy_features.get(pkg_id) {
-                    Some(feats) => feats.iter().cloned().collect(),
-                    None => BTreeSet::new(),
-                };
+                let old_features = legacy
+                    .activated_features
+                    .get(&(*pkg_id, *for_host))
+                    // The new features may have for_host entries where the old one does not.
+                    .or_else(|| legacy.activated_features.get(&(*pkg_id, false)))
+                    .map(|feats| feats.iter().cloned().collect())
+                    .unwrap_or_else(|| BTreeSet::new());
                 // The new resolver should never add features.
                 assert_eq!(new_features.difference(&old_features).next(), None);
                 let removed_features: BTreeSet<_> =
@@ -427,17 +388,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
     ) -> CargoResult<ResolvedFeatures> {
         use crate::util::profile;
         let _p = profile::start("resolve features");
-
-        if !opts.new_resolver {
-            // Legacy mode.
-            return Ok(ResolvedFeatures {
-                activated_features: HashMap::new(),
-                activated_dependencies: HashMap::new(),
-                legacy_features: Some(resolve.features_clone()),
-                legacy_dependencies: Some(compute_legacy_deps(resolve)),
-                opts,
-            });
-        }
         let track_for_host = opts.decouple_host_deps || opts.ignore_inactive_targets;
         let mut r = FeatureResolver {
             ws,
@@ -460,8 +410,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
         Ok(ResolvedFeatures {
             activated_features: r.activated_features,
             activated_dependencies: r.activated_dependencies,
-            legacy_features: None,
-            legacy_dependencies: None,
             opts: r.opts,
         })
     }
@@ -826,19 +774,3 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
             .proc_macro()
     }
 }
-
-/// Computes a map of PackageId to the set of optional dependencies that are
-/// enabled for that dep (when the new resolver is not enabled).
-fn compute_legacy_deps(resolve: &Resolve) -> HashMap<PackageId, HashSet<InternedString>> {
-    let mut result: HashMap<PackageId, HashSet<InternedString>> = HashMap::new();
-    for pkg_id in resolve.iter() {
-        for (_dep_id, deps) in resolve.deps(pkg_id) {
-            for dep in deps {
-                if dep.is_optional() {
-                    result.entry(pkg_id).or_default().insert(dep.name_in_toml());
-                }
-            }
-        }
-    }
-    result
-}
index 4f48fafa6f282947eeeb5faff0d6482967968f51..9c5396eecf5b7373933b99e8b554334523e4398f 100644 (file)
@@ -23,8 +23,6 @@ struct Inner {
     package_id: PackageId,
     dependencies: Vec<Dependency>,
     features: Rc<FeatureMap>,
-    has_namespaced_features: bool,
-    has_overlapping_features: Option<InternedString>,
     checksum: Option<String>,
     links: Option<InternedString>,
 }
@@ -37,15 +35,11 @@ impl Summary {
         features: &BTreeMap<InternedString, Vec<InternedString>>,
         links: Option<impl Into<InternedString>>,
     ) -> CargoResult<Summary> {
-        // ****CAUTION**** If you change anything here than may raise a new
+        // ****CAUTION**** If you change anything here that may raise a new
         // error, be sure to coordinate that change with either the index
         // schema field or the SummariesCache version.
-        let mut has_overlapping_features = None;
         for dep in dependencies.iter() {
             let dep_name = dep.name_in_toml();
-            if features.contains_key(&dep_name) {
-                has_overlapping_features = Some(dep_name);
-            }
             if dep.is_optional() && !dep.is_transitive() {
                 bail!(
                     "dev-dependencies are not allowed to be optional: `{}`",
@@ -53,8 +47,7 @@ impl Summary {
                 )
             }
         }
-        let (feature_map, has_namespaced_features) =
-            build_feature_map(config, pkg_id, features, &dependencies)?;
+        let feature_map = build_feature_map(config, pkg_id, features, &dependencies)?;
         Ok(Summary {
             inner: Rc::new(Inner {
                 package_id: pkg_id,
@@ -62,8 +55,6 @@ impl Summary {
                 features: Rc::new(feature_map),
                 checksum: None,
                 links: links.map(|l| l.into()),
-                has_namespaced_features,
-                has_overlapping_features,
             }),
         })
     }
@@ -87,46 +78,6 @@ impl Summary {
         &self.inner.features
     }
 
-    /// Returns an error if this Summary is using an unstable feature that is
-    /// not enabled.
-    pub fn unstable_gate(
-        &self,
-        namespaced_features: bool,
-        weak_dep_features: bool,
-    ) -> CargoResult<()> {
-        if !namespaced_features {
-            if self.inner.has_namespaced_features {
-                bail!(
-                    "namespaced features with the `dep:` prefix are only allowed on \
-                     the nightly channel and requires the `-Z namespaced-features` flag on the command-line"
-                );
-            }
-            if let Some(dep_name) = self.inner.has_overlapping_features {
-                bail!(
-                    "features and dependencies cannot have the same name: `{}`",
-                    dep_name
-                )
-            }
-        }
-        if !weak_dep_features {
-            for (feat_name, features) in self.features() {
-                for fv in features {
-                    if matches!(fv, FeatureValue::DepFeature { weak: true, .. }) {
-                        bail!(
-                            "optional dependency features with `?` syntax are only \
-                             allowed on the nightly channel and requires the \
-                             `-Z weak-dep-features` flag on the command line\n\
-                             Feature `{}` had feature value `{}`.",
-                            feat_name,
-                            fv
-                        );
-                    }
-                }
-            }
-        }
-        Ok(())
-    }
-
     pub fn checksum(&self) -> Option<&str> {
         self.inner.checksum.as_deref()
     }
@@ -181,16 +132,12 @@ impl Hash for Summary {
 
 /// Checks features for errors, bailing out a CargoResult:Err if invalid,
 /// and creates FeatureValues for each feature.
-///
-/// The returned `bool` indicates whether or not the `[features]` table
-/// included a `dep:` prefixed namespaced feature (used for gating on
-/// nightly).
 fn build_feature_map(
     config: &Config,
     pkg_id: PackageId,
     features: &BTreeMap<InternedString, Vec<InternedString>>,
     dependencies: &[Dependency],
-) -> CargoResult<(FeatureMap, bool)> {
+) -> CargoResult<FeatureMap> {
     use self::FeatureValue::*;
     let mut dep_map = HashMap::new();
     for dep in dependencies.iter() {
@@ -210,7 +157,6 @@ fn build_feature_map(
             (*feature, fvs)
         })
         .collect();
-    let has_namespaced_features = map.values().flatten().any(|fv| fv.has_dep_prefix());
 
     // Add implicit features for optional dependencies if they weren't
     // explicitly listed anywhere.
@@ -372,7 +318,7 @@ fn build_feature_map(
         );
     }
 
-    Ok((map, has_namespaced_features))
+    Ok(map)
 }
 
 /// FeatureValue represents the types of dependencies a feature can have.
index b2e100f6c0bb9b73245e9ccaf90f7d91bbc69f04..8cb3951dd4d351e2eab7b684a1a02a61734a4da5 100644 (file)
@@ -31,9 +31,8 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
             VERSION
         );
     }
-    let config = ws.config();
     let (packages, resolve) = if opt.no_deps {
-        let packages = ws.members().map(|pkg| pkg.serialized(config)).collect();
+        let packages = ws.members().map(|pkg| pkg.serialized()).collect();
         (packages, None)
     } else {
         let (packages, resolve) = build_resolve_graph(ws, opt)?;
@@ -152,11 +151,10 @@ fn build_resolve_graph(
         );
     }
     // Get a Vec of Packages.
-    let config = ws.config();
     let actual_packages = package_map
         .into_iter()
         .filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg))
-        .map(|pkg| pkg.serialized(config))
+        .map(|pkg| pkg.serialized())
         .collect();
 
     let mr = MetadataResolve {
index fe0a9469272fbbff57c0f31d7d483a6ff75d9721..b8e47d9218f26df849c4ddef78ef28dc595cdbff 100644 (file)
@@ -287,7 +287,6 @@ fn transmit(
                 license_file: license_file.clone(),
                 badges: badges.clone(),
                 links: links.clone(),
-                v: None,
             },
             tarball,
         )
index 3d873acd38810f77e29f9cfe1b6381a50586a7b4..1394d9c1ab64eebdfbd5c7fc926ba8090b4bcaff 100644 (file)
@@ -293,8 +293,6 @@ impl<'cfg> RegistryIndex<'cfg> {
     {
         let source_id = self.source_id;
         let config = self.config;
-        let namespaced_features = self.config.cli_unstable().namespaced_features;
-        let weak_dep_features = self.config.cli_unstable().weak_dep_features;
 
         // First up actually parse what summaries we have available. If Cargo
         // has run previously this will parse a Cargo-specific cache file rather
@@ -309,11 +307,6 @@ impl<'cfg> RegistryIndex<'cfg> {
         // minimize the amount of work being done here and parse as little as
         // necessary.
         let raw_data = &summaries.raw_data;
-        let max_version = if namespaced_features || weak_dep_features {
-            INDEX_V_MAX
-        } else {
-            1
-        };
         Ok(summaries
             .versions
             .iter_mut()
@@ -328,7 +321,7 @@ impl<'cfg> RegistryIndex<'cfg> {
                 },
             )
             .filter(move |is| {
-                if is.v > max_version {
+                if is.v > INDEX_V_MAX {
                     debug!(
                         "unsupported schema version {} ({} {})",
                         is.v,
@@ -339,11 +332,6 @@ impl<'cfg> RegistryIndex<'cfg> {
                 } else {
                     true
                 }
-            })
-            .filter(move |is| {
-                is.summary
-                    .unstable_gate(namespaced_features, weak_dep_features)
-                    .is_ok()
             }))
     }
 
index 39835c75285e78e1f23623d6612d4ed4d94e8baf..0b09c16914b6d2cda77b1bf9c9551394855c9dcd 100644 (file)
@@ -1299,8 +1299,6 @@ impl TomlManifest {
             me.features.as_ref().unwrap_or(&empty_features),
             project.links.as_deref(),
         )?;
-        let unstable = config.cli_unstable();
-        summary.unstable_gate(unstable.namespaced_features, unstable.weak_dep_features)?;
 
         let metadata = ManifestMetadata {
             description: project.description.clone(),
index 0defb30b79465b30824b45471cfb6bbeb9aa46e6..612f341a5d3d60dee0756759f2f0a2101b972aca 100644 (file)
@@ -116,21 +116,33 @@ an external package to handle GIF images. This can be expressed like this:
 gif = { version = "0.11.1", optional = true }
 ```
 
-Optional dependencies implicitly define a feature of the same name as the
-dependency. This means that the same `cfg(feature = "gif")` syntax can be used
-in the code, and the dependency can be enabled just like a feature such as
-`--features gif` (see [Command-line feature
-options](#command-line-feature-options) below).
-
-> **Note**: A feature in the `[feature]` table cannot use the same name as a
-> dependency. Experimental support for enabling this and other extensions is
-> available on the nightly channel via [namespaced
-> features](unstable.md#namespaced-features).
-
-Explicitly defined features can enable optional dependencies, too. Just
-include the name of the optional dependency in the feature list. For example,
-let's say in order to support the AVIF image format, our library needs two
-other dependencies to be enabled:
+By default, this optional dependency implicitly defines a feature that looks
+like this:
+
+```toml
+[features]
+gif = ["dep:gif"]
+```
+
+This means that this dependency will only be included if the `gif`
+feature is enabled.
+The same `cfg(feature = "gif")` syntax can be used in the code, and the
+dependency can be enabled just like any feature such as `--features gif` (see
+[Command-line feature options](#command-line-feature-options) below).
+
+In some cases, you may not want to expose a feature that has the same name
+as the optional dependency.
+For example, perhaps the optional dependency is an internal detail, or you
+want to group multiple optional dependencies together, or you just want to use
+a better name.
+If you specify the optional dependency with the `dep:` prefix anywhere
+in the `[features]` table, that disables the implicit feature.
+
+> **Note**: The `dep:` syntax is only available starting with Rust 1.60.
+> Previous versions can only use the implicit feature name.
+
+For example, let's say in order to support the AVIF image format, our library
+needs two other dependencies to be enabled:
 
 ```toml
 [dependencies]
@@ -138,10 +150,13 @@ ravif = { version = "0.6.3", optional = true }
 rgb = { version = "0.8.25", optional = true }
 
 [features]
-avif = ["ravif", "rgb"]
+avif = ["dep:ravif", "dep:rgb"]
 ```
 
 In this example, the `avif` feature will enable the two listed dependencies.
+This also avoids creating the implicit `ravif` and `rgb` features, since we
+don't want users to enable those individually as they are internal details to
+our crate.
 
 > **Note**: Another way to optionally include a dependency is to use
 > [platform-specific dependencies]. Instead of using features, these are
@@ -185,10 +200,31 @@ jpeg-decoder = { version = "0.1.20", default-features = false }
 parallel = ["jpeg-decoder/rayon"]
 ```
 
-> **Note**: The `"package-name/feature-name"` syntax will also enable
-> `package-name` if it is an optional dependency. Experimental support for
-> disabling that behavior is available on the nightly channel via [weak
-> dependency features](unstable.md#weak-dependency-features).
+The `"package-name/feature-name"` syntax will also enable `package-name`
+if it is an optional dependency. Often this is not what you want.
+You can add a `?` as in `"package-name?/feature-name"` which will only enable
+the given feature if something else enables the optional dependency.
+
+> **Note**: The `?` syntax is only available starting with Rust 1.60.
+
+For example, let's say we have added some serialization support to our
+library, and it requires enabling a corresponding feature in some optional
+dependencies.
+That can be done like this:
+
+```toml
+[dependencies]
+serde = { version = "1.0.133", optional = true }
+rgb = { version = "0.8.25", optional = true }
+
+[features]
+serde = ["dep:serde", "rgb?/serde"]
+```
+
+In this example, enabling the `serde` feature will enable the serde
+dependency.
+It will also enable the `serde` feature for the `rgb` dependency, but only if
+something else has enabled the `rgb` dependency.
 
 ### Command-line feature options
 
index ef23caeee1fca375340303cfc0e4af0e209c5f9e..45af03236f4ed63ea254010253e13a7e3f172dab 100644 (file)
@@ -263,7 +263,45 @@ explaining the format of the entry.
     "yanked": false,
     // The `links` string value from the package's manifest, or null if not
     // specified. This field is optional and defaults to null.
-    "links": null
+    "links": null,
+    // An unsigned 32-bit integer value indicating the schema version of this
+    // entry.
+    //
+    // If this not specified, it should be interpreted as the default of 1.
+    //
+    // Cargo (starting with version 1.51) will ignore versions it does not
+    // recognize. This provides a method to safely introduce changes to index
+    // entries and allow older versions of cargo to ignore newer entries it
+    // doesn't understand. Versions older than 1.51 ignore this field, and
+    // thus may misinterpret the meaning of the index entry.
+    //
+    // The current values are:
+    //
+    // * 1: The schema as documented here, not including newer additions.
+    //      This is honored in Rust version 1.51 and newer.
+    // * 2: The addition of the `features2` field.
+    //      This is honored in Rust version 1.60 and newer.
+    "v": 2,
+    // This optional field contains features with new, extended syntax.
+    // Specifically, namespaced features (`dep:`) and weak dependencies
+    // (`pkg?/feat`).
+    //
+    // This is separated from `features` because versions older than 1.19
+    // will fail to load due to not being able to parse the new syntax, even
+    // with a `Cargo.lock` file.
+    //
+    // Cargo will merge any values listed here with the "features" field.
+    //
+    // If this field is included, the "v" field should be set to at least 2.
+    //
+    // Registries are not required to use this field for extended feature
+    // syntax, they are allowed to include those in the "features" field.
+    // Using this is only necessary if the registry wants to support cargo
+    // versions older than 1.19, which in practice is only crates.io since
+    // those older versions do not support other registries.
+    "features2": {
+        "serde": ["dep:serde", "chrono?/serde"]
+    }
 }
 ```
 
index ff29e8f2bc5e7cc66278500bd4dcfe257328506c..48917ad4a47c628ce9f4e8526fa0a40e81274569 100644 (file)
@@ -69,8 +69,6 @@ Each new feature described below should explain how to use it.
     * [avoid-dev-deps](#avoid-dev-deps) — Prevents the resolver from including dev-dependencies during resolution.
     * [minimal-versions](#minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest.
     * [public-dependency](#public-dependency) — Allows dependencies to be classified as either public or private.
-    * [Namespaced features](#namespaced-features) — Separates optional dependencies into a separate namespace from regular features, and allows feature names to be the same as some dependency name.
-    * [Weak dependency features](#weak-dependency-features) — Allows setting features for dependencies without enabling optional dependencies.
 * Output behavior
     * [out-dir](#out-dir) — Adds a directory where artifacts are copied to.
     * [terminal-width](#terminal-width) — Tells rustc the width of the terminal so that long diagnostic messages can be truncated to be more readable.
@@ -252,68 +250,6 @@ dir-name = "lto"  # Emits to target/lto instead of target/release-lto
 lto = true
 ```
 
-
-### Namespaced features
-* Original issue: [#1286](https://github.com/rust-lang/cargo/issues/1286)
-* Tracking Issue: [#5565](https://github.com/rust-lang/cargo/issues/5565)
-
-The `namespaced-features` option makes two changes to how features can be
-specified:
-
-* Features may now be defined with the same name as a dependency.
-* Optional dependencies can be explicitly enabled in the `[features]` table
-  with the `dep:` prefix, which enables the dependency without enabling a
-  feature of the same name.
-
-By default, an optional dependency `foo` will define a feature `foo =
-["dep:foo"]` *unless* `dep:foo` is mentioned in any other feature, or the
-`foo` feature is already defined. This helps prevent unnecessary boilerplate
-of listing every optional dependency, but still allows you to override the
-implicit feature.
-
-This allows two use cases that were previously not possible:
-
-* You can "hide" an optional dependency, so that external users cannot
-  explicitly enable that optional dependency.
-* There is no longer a need to create "funky" feature names to work around the
-  restriction that features cannot shadow dependency names.
-
-To enable namespaced-features, use the `-Z namespaced-features` command-line
-flag.
-
-An example of hiding an optional dependency:
-
-```toml
-[dependencies]
-regex = { version = "1.4.1", optional = true }
-lazy_static = { version = "1.4.0", optional = true }
-
-[features]
-regex = ["dep:regex", "dep:lazy_static"]
-```
-
-In this example, the "regex" feature enables both `regex` and `lazy_static`.
-The `lazy_static` feature does not exist, and a user cannot explicitly enable
-it. This helps hide internal details of how your package is implemented.
-
-An example of avoiding "funky" names:
-
-```toml
-[dependencies]
-bigdecimal = "0.1"
-chrono = "0.4"
-num-bigint = "0.2"
-serde = {version = "1.0", optional = true }
-
-[features]
-serde = ["dep:serde", "bigdecimal/serde", "chrono/serde", "num-bigint/serde"]
-```
-
-In this case, `serde` is a natural name to use for a feature, because it is
-relevant to your exported API. However, previously you would need to use a
-name like `serde1` to work around the naming limitation if you wanted to also
-enable other features.
-
 ### Build-plan
 * Tracking Issue: [#5579](https://github.com/rust-lang/cargo/issues/5579)
 
@@ -898,29 +834,6 @@ error[E0308]: mismatched types
 error: aborting due to previous error
 ```
 
-### Weak dependency features
-* Tracking Issue: [#8832](https://github.com/rust-lang/cargo/issues/8832)
-
-The `-Z weak-dep-features` command-line options enables the ability to use
-`dep_name?/feat_name` syntax in the `[features]` table. The `?` indicates that
-the optional dependency `dep_name` will not be automatically enabled. The
-feature `feat_name` will only be added if something else enables the
-`dep_name` dependency.
-
-Example:
-
-```toml
-[dependencies]
-serde = { version = "1.0.117", optional = true, default-features = false }
-
-[features]
-std = ["serde?/std"]
-```
-
-In this example, the `std` feature enables the `std` feature on the `serde`
-dependency. However, unlike the normal `serde/std` syntax, it will not enable
-the optional dependency `serde` unless something else has included it.
-
 ### per-package-target
 * Tracking Issue: [#9406](https://github.com/rust-lang/cargo/pull/9406)
 * Original Pull Request: [#9030](https://github.com/rust-lang/cargo/pull/9030)
@@ -1375,3 +1288,13 @@ The profile `strip` option has been stabilized in the 1.59 release. See the
 Support for generating a future-incompat report has been stabilized
 in the 1.59 release. See the [future incompat report chapter](future-incompat-report.md)
 for more information.
+
+### Namespaced features
+
+Namespaced features has been stabilized in the 1.60 release.
+See the [Features chapter](features.md#optional-dependencies) for more information.
+
+### Weak dependency features
+
+Weak dependency features has been stabilized in the 1.60 release.
+See the [Features chapter](features.md#dependency-features) for more information.
index 49a61301bac1a744d5fb4b244b9ce7849e82395e..8a8ed78e595c504b28a1a0080e3b743fd02b727d 100644 (file)
@@ -36,7 +36,8 @@ Caused by:
 }
 
 #[cargo_test]
-fn invalid2() {
+fn same_name() {
+    // Feature with the same name as a dependency.
     let p = project()
         .file(
             "Cargo.toml",
@@ -59,14 +60,24 @@ fn invalid2() {
         .file("bar/src/lib.rs", "")
         .build();
 
-    p.cargo("build")
-        .with_status(101)
-        .with_stderr(
+    p.cargo("tree -f")
+        .arg("{p} [{f}]")
+        .with_stderr("")
+        .with_stdout(
             "\
-[ERROR] failed to parse manifest at `[..]`
+foo v0.0.1 ([..]) []
+└── bar v1.0.0 ([..]) []
+",
+        )
+        .run();
 
-Caused by:
-  features and dependencies cannot have the same name: `bar`
+    p.cargo("tree --features bar -f")
+        .arg("{p} [{f}]")
+        .with_stderr("")
+        .with_stdout(
+            "\
+foo v0.0.1 ([..]) [bar,baz]
+└── bar v1.0.0 ([..]) []
 ",
         )
         .run();
index 5b5ea47e7be80ab05532a36c8a78b861bf84d3c4..78cdc2b151042ba91161231efd9886cdfade02ba 100644 (file)
@@ -4,99 +4,6 @@ use super::features2::switch_to_resolver_2;
 use cargo_test_support::registry::{Dependency, Package};
 use cargo_test_support::{project, publish};
 
-#[cargo_test]
-fn gated() {
-    // Need namespaced-features to use `dep:` syntax.
-    Package::new("bar", "1.0.0").publish();
-    let p = project()
-        .file(
-            "Cargo.toml",
-            r#"
-                [package]
-                name = "foo"
-                version = "0.1.0"
-
-                [dependencies]
-                bar = { version = "1.0", optional = true }
-
-                [features]
-                foo = ["dep:bar"]
-            "#,
-        )
-        .file("src/lib.rs", "")
-        .build();
-
-    p.cargo("check")
-        .with_status(101)
-        .with_stderr(
-            "\
-[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
-
-Caused by:
-  namespaced features with the `dep:` prefix are only allowed on the nightly channel \
-  and requires the `-Z namespaced-features` flag on the command-line
-",
-        )
-        .run();
-}
-
-#[cargo_test]
-fn dependency_gate_ignored() {
-    // Dependencies with `dep:` features are ignored in the registry if not on nightly.
-    Package::new("baz", "1.0.0").publish();
-    Package::new("bar", "1.0.0")
-        .add_dep(Dependency::new("baz", "1.0").optional(true))
-        .feature("feat", &["dep:baz"])
-        .publish();
-    let p = project()
-        .file(
-            "Cargo.toml",
-            r#"
-                [package]
-                name = "foo"
-                version = "0.1.0"
-
-                [dependencies]
-                bar = "1.0"
-            "#,
-        )
-        .file("src/lib.rs", "")
-        .build();
-
-    p.cargo("check")
-        .masquerade_as_nightly_cargo()
-        .with_status(101)
-        .with_stderr(
-            "\
-[UPDATING] [..]
-[ERROR] no matching package named `bar` found
-location searched: registry `crates-io`
-required by package `foo v0.1.0 ([..]/foo)`
-",
-        )
-        .run();
-
-    // Publish a version without namespaced features, it should ignore 1.0.0
-    // and use this instead.
-    Package::new("bar", "1.0.1")
-        .add_dep(Dependency::new("baz", "1.0").optional(true))
-        .feature("feat", &["baz"])
-        .publish();
-    p.cargo("check")
-        .masquerade_as_nightly_cargo()
-        .with_stderr(
-            "\
-[UPDATING] [..]
-[DOWNLOADING] crates ...
-[DOWNLOADED] bar [..]
-[CHECKING] bar v1.0.1
-[CHECKING] foo v0.1.0 [..]
-[FINISHED] [..]
-",
-        )
-        .run();
-}
-
 #[cargo_test]
 fn dependency_with_crate_syntax() {
     // Registry dependency uses dep: syntax.
@@ -120,8 +27,7 @@ fn dependency_with_crate_syntax() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("check -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -156,8 +62,7 @@ fn namespaced_invalid_feature() {
         .file("src/main.rs", "")
         .build();
 
-    p.cargo("build -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("build")
         .with_status(101)
         .with_stderr(
             "\
@@ -188,8 +93,7 @@ fn namespaced_invalid_dependency() {
         .file("src/main.rs", "")
         .build();
 
-    p.cargo("build -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("build")
         .with_status(101)
         .with_stderr(
             "\
@@ -223,8 +127,8 @@ fn namespaced_non_optional_dependency() {
         .file("src/main.rs", "")
         .build();
 
-    p.cargo("build -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("build")
+
         .with_status(101)
         .with_stderr(
             "\
@@ -261,8 +165,7 @@ fn namespaced_implicit_feature() {
         .file("src/main.rs", "fn main() {}")
         .build();
 
-    p.cargo("check -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -271,8 +174,7 @@ fn namespaced_implicit_feature() {
 ",
         )
         .run();
-    p.cargo("check -Z namespaced-features --features baz")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features baz")
         .with_stderr(
             "\
 [DOWNLOADING] crates ...
@@ -307,8 +209,7 @@ fn namespaced_shadowed_dep() {
         .file("src/main.rs", "fn main() {}")
         .build();
 
-    p.cargo("build -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("build")
         .with_status(101)
         .with_stderr(
             "\
@@ -344,9 +245,7 @@ fn namespaced_shadowed_non_optional() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("check -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
-        .run();
+    p.cargo("check").run();
 }
 
 #[cargo_test]
@@ -370,7 +269,7 @@ fn namespaced_implicit_non_optional() {
         .file("src/main.rs", "fn main() {}")
         .build();
 
-    p.cargo("build -Z namespaced-features").masquerade_as_nightly_cargo().with_status(101).with_stderr(
+    p.cargo("build").with_status(101).with_stderr(
         "\
 [ERROR] failed to parse manifest at `[..]`
 
@@ -411,8 +310,7 @@ fn namespaced_same_name() {
         )
         .build();
 
-    p.cargo("run -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("run")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -424,8 +322,7 @@ fn namespaced_same_name() {
         .with_stdout("")
         .run();
 
-    p.cargo("run -Z namespaced-features --features baz")
-        .masquerade_as_nightly_cargo()
+    p.cargo("run --features baz")
         .with_stderr(
             "\
 [DOWNLOADING] crates ...
@@ -473,8 +370,7 @@ fn no_implicit_feature() {
         )
         .build();
 
-    p.cargo("run -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("run")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -486,8 +382,7 @@ fn no_implicit_feature() {
         .with_stdout("")
         .run();
 
-    p.cargo("run -Z namespaced-features --features regex")
-        .masquerade_as_nightly_cargo()
+    p.cargo("run --features regex")
         .with_stderr_unordered(
             "\
 [DOWNLOADING] crates ...
@@ -503,8 +398,7 @@ fn no_implicit_feature() {
         .with_stdout("regex")
         .run();
 
-    p.cargo("run -Z namespaced-features --features lazy_static")
-        .masquerade_as_nightly_cargo()
+    p.cargo("run --features lazy_static")
         .with_stderr(
             "\
 [ERROR] Package `foo v0.1.0 [..]` does not have feature `lazy_static`. \
@@ -538,8 +432,7 @@ fn crate_syntax_bad_name() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("check -Z namespaced-features --features dep:bar")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features dep:bar")
         .with_status(101)
         .with_stderr(
             "\
@@ -574,8 +467,7 @@ fn crate_syntax_in_dep() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("check -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_status(101)
         .with_stderr(
             "\
@@ -608,8 +500,7 @@ fn crate_syntax_cli() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("check -Z namespaced-features --features dep:bar")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features dep:bar")
         .with_status(101)
         .with_stderr(
             "\
@@ -619,8 +510,7 @@ fn crate_syntax_cli() {
         .run();
 
     switch_to_resolver_2(&p);
-    p.cargo("check -Z namespaced-features --features dep:bar")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features dep:bar")
         .with_status(101)
         .with_stderr(
             "\
@@ -653,8 +543,7 @@ fn crate_required_features() {
         .file("src/main.rs", "fn main() {}")
         .build();
 
-    p.cargo("check -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_status(101)
         .with_stderr(
             "\
@@ -685,8 +574,7 @@ fn json_exposed() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("metadata -Z namespaced-features --no-deps")
-        .masquerade_as_nightly_cargo()
+    p.cargo("metadata --no-deps")
         .with_json(
             r#"
                 {
@@ -775,8 +663,7 @@ fn crate_feature_with_explicit() {
         )
         .build();
 
-    p.cargo("check -Z namespaced-features --features f1")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features f1")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -814,8 +701,7 @@ fn optional_explicit_without_crate() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("build -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("build")
         .with_status(101)
         .with_stderr(
             "\
@@ -856,13 +742,11 @@ fn tree() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("tree -e features -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features")
         .with_stdout("foo v0.1.0 ([ROOT]/foo)")
         .run();
 
-    p.cargo("tree -e features --features a -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features --features a")
         .with_stdout(
             "\
 foo v0.1.0 ([ROOT]/foo)
@@ -876,8 +760,7 @@ foo v0.1.0 ([ROOT]/foo)
         )
         .run();
 
-    p.cargo("tree -e features --features a -i bar -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features --features a -i bar")
         .with_stdout(
             "\
 bar v1.0.0
@@ -895,8 +778,7 @@ bar v1.0.0
         )
         .run();
 
-    p.cargo("tree -e features --features bar -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features --features bar")
         .with_stdout(
             "\
 foo v0.1.0 ([ROOT]/foo)
@@ -910,8 +792,7 @@ foo v0.1.0 ([ROOT]/foo)
         )
         .run();
 
-    p.cargo("tree -e features --features bar -i bar -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features --features bar -i bar")
         .with_stdout(
             "\
 bar v1.0.0
@@ -948,13 +829,11 @@ fn tree_no_implicit() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("tree -e features -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features")
         .with_stdout("foo v0.1.0 ([ROOT]/foo)")
         .run();
 
-    p.cargo("tree -e features --all-features -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features --all-features")
         .with_stdout(
             "\
 foo v0.1.0 ([ROOT]/foo)
@@ -964,8 +843,7 @@ foo v0.1.0 ([ROOT]/foo)
         )
         .run();
 
-    p.cargo("tree -e features -i bar --all-features -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features -i bar --all-features")
         .with_stdout(
             "\
 bar v1.0.0
@@ -1116,8 +994,7 @@ fn publish() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("publish --token sekrit -Z namespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("publish --token sekrit")
         .with_stderr(
             "\
 [UPDATING] [..]
index 10179bc2b9bc4532f1bd9b849e1137d65222c912..b3d1e3ca5d592c391b25923ccebf0d337304a132 100644 (file)
@@ -558,8 +558,7 @@ fn index_cache_rebuild() {
     fs::remove_file(p.root().join("Cargo.lock")).unwrap();
 
     // This should rebuild the cache and use 1.0.1.
-    p.cargo("check -Znamespaced-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_stderr(
             "\
 [UPDATING] [..]
index 42c4fcdc5e2f65d3544b5256195f092dea921907..6d7d8857dd09d0081832ea76f4311abee60904f0 100644 (file)
@@ -20,100 +20,6 @@ fn require(enabled_features: &[&str], disabled_features: &[&str]) -> String {
     s
 }
 
-#[cargo_test]
-fn gated() {
-    // Need -Z weak-dep-features to enable.
-    Package::new("bar", "1.0.0").feature("feat", &[]).publish();
-    let p = project()
-        .file(
-            "Cargo.toml",
-            r#"
-                [package]
-                name = "foo"
-                version = "0.1.0"
-
-                [dependencies]
-                bar = { version = "1.0", optional = true }
-
-                [features]
-                f1 = ["bar?/feat"]
-            "#,
-        )
-        .file("src/lib.rs", "")
-        .build();
-    p.cargo("check")
-        .with_status(101)
-        .with_stderr(
-            "\
-error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
-
-Caused by:
-  optional dependency features with `?` syntax are only allowed on the nightly \
-  channel and requires the `-Z weak-dep-features` flag on the command line
-  Feature `f1` had feature value `bar?/feat`.
-",
-        )
-        .run();
-}
-
-#[cargo_test]
-fn dependency_gate_ignored() {
-    // Dependencies with ? features in the registry are ignored in the
-    // registry if not on nightly.
-    Package::new("baz", "1.0.0").feature("feat", &[]).publish();
-    Package::new("bar", "1.0.0")
-        .add_dep(Dependency::new("baz", "1.0").optional(true))
-        .feature("feat", &["baz?/feat"])
-        .publish();
-    let p = project()
-        .file(
-            "Cargo.toml",
-            r#"
-                [package]
-                name = "foo"
-                version = "0.1.0"
-
-                [dependencies]
-                bar = "1.0"
-            "#,
-        )
-        .file("src/lib.rs", "")
-        .build();
-
-    p.cargo("check")
-        .masquerade_as_nightly_cargo()
-        .with_status(101)
-        .with_stderr(
-            "\
-[UPDATING] [..]
-[ERROR] no matching package named `bar` found
-location searched: registry `crates-io`
-required by package `foo v0.1.0 ([..]/foo)`
-",
-        )
-        .run();
-
-    // Publish a version without the ? feature, it should ignore 1.0.0
-    // and use this instead.
-    Package::new("bar", "1.0.1")
-        .add_dep(Dependency::new("baz", "1.0").optional(true))
-        .feature("feat", &["baz"])
-        .publish();
-    p.cargo("check")
-        .masquerade_as_nightly_cargo()
-        .with_stderr(
-            "\
-[UPDATING] [..]
-[DOWNLOADING] crates ...
-[DOWNLOADED] bar [..]
-[CHECKING] bar v1.0.1
-[CHECKING] foo v0.1.0 [..]
-[FINISHED] [..]
-",
-        )
-        .run();
-}
-
 #[cargo_test]
 fn simple() {
     Package::new("bar", "1.0.0")
@@ -140,8 +46,7 @@ fn simple() {
 
     // It's a bit unfortunate that this has to download `bar`, but avoiding
     // that is extremely difficult.
-    p.cargo("check -Z weak-dep-features --features f1")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features f1")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -153,8 +58,7 @@ fn simple() {
         )
         .run();
 
-    p.cargo("check -Z weak-dep-features --features f1,bar")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features f1,bar")
         .with_stderr(
             "\
 [CHECKING] bar v1.0.0
@@ -196,8 +100,7 @@ fn deferred() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("check -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -238,8 +141,7 @@ fn not_optional_dep() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("check -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_status(101)
         .with_stderr("\
 error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
@@ -275,8 +177,7 @@ fn optional_cli_syntax() {
         .build();
 
     // Does not build bar.
-    p.cargo("check --features bar?/feat -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features bar?/feat")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -289,8 +190,7 @@ fn optional_cli_syntax() {
         .run();
 
     // Builds bar.
-    p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features bar?/feat,bar")
         .with_stderr(
             "\
 [CHECKING] bar v1.0.0
@@ -304,8 +204,7 @@ fn optional_cli_syntax() {
     switch_to_resolver_2(&p);
     p.build_dir().rm_rf();
     // Does not build bar.
-    p.cargo("check --features bar?/feat -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features bar?/feat")
         .with_stderr(
             "\
 [CHECKING] foo v0.1.0 [..]
@@ -315,8 +214,7 @@ fn optional_cli_syntax() {
         .run();
 
     // Builds bar.
-    p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features bar?/feat,bar")
         .with_stderr(
             "\
 [CHECKING] bar v1.0.0
@@ -351,8 +249,7 @@ fn required_features() {
         .file("src/main.rs", "fn main() {}")
         .build();
 
-    p.cargo("check -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check")
         .with_status(101)
         .with_stderr(
             "\
@@ -366,7 +263,7 @@ optional dependency with `?` is not allowed in required-features
 
 #[cargo_test]
 fn weak_with_host_decouple() {
-    // -Z weak-opt-features with new resolver
+    // weak-dep-features with new resolver
     //
     // foo v0.1.0
     // └── common v1.0.0
@@ -447,8 +344,7 @@ fn weak_with_host_decouple() {
         )
         .build();
 
-    p.cargo("run -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("run")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -493,8 +389,7 @@ fn weak_namespaced() {
         .file("src/lib.rs", &require(&["f1"], &["f2", "bar"]))
         .build();
 
-    p.cargo("check -Z weak-dep-features -Z namespaced-features --features f1")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features f1")
         .with_stderr(
             "\
 [UPDATING] [..]
@@ -506,21 +401,18 @@ fn weak_namespaced() {
         )
         .run();
 
-    p.cargo("tree -Z weak-dep-features -Z namespaced-features -f")
+    p.cargo("tree -f")
         .arg("{p} feats:{f}")
-        .masquerade_as_nightly_cargo()
         .with_stdout("foo v0.1.0 ([ROOT]/foo) feats:")
         .run();
 
-    p.cargo("tree -Z weak-dep-features -Z namespaced-features --features f1 -f")
+    p.cargo("tree --features f1 -f")
         .arg("{p} feats:{f}")
-        .masquerade_as_nightly_cargo()
         .with_stdout("foo v0.1.0 ([ROOT]/foo) feats:f1")
         .run();
 
-    p.cargo("tree -Z weak-dep-features -Z namespaced-features --features f1,f2 -f")
+    p.cargo("tree --features f1,f2 -f")
         .arg("{p} feats:{f}")
-        .masquerade_as_nightly_cargo()
         .with_stdout(
             "\
 foo v0.1.0 ([ROOT]/foo) feats:f1,f2
@@ -532,8 +424,7 @@ foo v0.1.0 ([ROOT]/foo) feats:f1,f2
     // "bar" remains not-a-feature
     p.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"]));
 
-    p.cargo("check -Z weak-dep-features -Z namespaced-features --features f1,f2")
-        .masquerade_as_nightly_cargo()
+    p.cargo("check --features f1,f2")
         .with_stderr(
             "\
 [CHECKING] bar v1.0.0
@@ -568,13 +459,11 @@ fn tree() {
         .file("src/lib.rs", &require(&["f1"], &[]))
         .build();
 
-    p.cargo("tree -Z weak-dep-features --features f1")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree --features f1")
         .with_stdout("foo v0.1.0 ([ROOT]/foo)")
         .run();
 
-    p.cargo("tree -Z weak-dep-features --features f1,bar")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree --features f1,bar")
         .with_stdout(
             "\
 foo v0.1.0 ([ROOT]/foo)
@@ -583,8 +472,7 @@ foo v0.1.0 ([ROOT]/foo)
         )
         .run();
 
-    p.cargo("tree -Z weak-dep-features --features f1,bar -e features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree --features f1,bar -e features")
         .with_stdout(
             "\
 foo v0.1.0 ([ROOT]/foo)
@@ -594,8 +482,7 @@ foo v0.1.0 ([ROOT]/foo)
         )
         .run();
 
-    p.cargo("tree -Z weak-dep-features --features f1,bar -e features -i bar")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree --features f1,bar -e features -i bar")
         .with_stdout(
             "\
 bar v1.0.0
@@ -610,20 +497,17 @@ bar v1.0.0
         )
         .run();
 
-    p.cargo("tree -Z weak-dep-features -e features --features bar?/feat")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features --features bar?/feat")
         .with_stdout("foo v0.1.0 ([ROOT]/foo)")
         .run();
 
     // This is a little strange in that it produces no output.
     // Maybe `cargo tree` should print a note about why?
-    p.cargo("tree -Z weak-dep-features -e features -i bar --features bar?/feat")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features -i bar --features bar?/feat")
         .with_stdout("")
         .run();
 
-    p.cargo("tree -Z weak-dep-features -e features -i bar --features bar?/feat,bar")
-        .masquerade_as_nightly_cargo()
+    p.cargo("tree -e features -i bar --features bar?/feat,bar")
         .with_stdout(
             "\
 bar v1.0.0
@@ -663,8 +547,7 @@ fn publish() {
         .file("src/lib.rs", "")
         .build();
 
-    p.cargo("publish --token sekrit -Z weak-dep-features")
-        .masquerade_as_nightly_cargo()
+    p.cargo("publish --token sekrit")
         .with_stderr(
             "\
 [UPDATING] [..]