Compare commits

...

63 Commits

Author SHA1 Message Date
Ed Page 024ac489a9 fix(toml)!: Remove support for inheriting badges
We allowed `[badges]` to inherit from `[workspace.package.badges]`

This was a bug:
- This was not specified in the RFC
- We did not document this
- Even if someone were to try to guess to use this, it is inconsistent
  with how inheritance works because this should inherit from
  `workspace.badges` instead of `workspace.package.badges`

While keeping in mind that `[badges]` is effectively deprecated.

In that context, I think its safe to break support for this without a
transition period.

Fixes #13643
2024-04-22 14:22:01 -05:00
bors eee4ea2f5a Auto merge of #13812 - Muscraft:dont-always-inherit-workspace-lints, r=epage
fix(cargo-lints): Don't always inherit workspace lints

When working on changes for #13805, I noticed that we always passed the contents of `[workspace.lints.cargo]` into the currently implemented lints,  even if `[lints]` was not specified or did not contain `workspace = true`. This PR makes it so we only pass in the workspace cargo lints if `[lints]` contains `workspace = true`.

You can verify this change by looking at the first commit, where I added a test showing the current behavior, and looking at the second commit and seeing the test output no longer shows a warning about specifying `im-a-teapot`.
2024-04-27 00:56:12 +00:00
bors c4e19cc890 Auto merge of #13811 - ehuss:remove-sleep-test, r=weihanglo
Update SleepTraker returns_in_order unit test

This updates the `returns_in_order` SleepTracker unit test so that it is not so sensitive to how fast the system is running. Previously it assumed that the function calls would take less than a millisecond to finish, but that is not a valid assumption for a slow-running system.

I have changed it to simplify the test, with the assumption that it takes less than 30 seconds for it to run, which should have a safety margin of a few orders of magnitude.
2024-04-26 23:30:40 +00:00
Eric Huss 06fb65e753 Update SleepTraker returns_in_order unit test 2024-04-26 16:02:09 -07:00
Scott Schafer cf197fc499
fix(cargo-lints): Don't always inherit workspace lints 2024-04-26 16:37:41 -06:00
Scott Schafer c3b104e11e
test(cargo-lints): Show workspace lints always inherited 2024-04-26 16:26:36 -06:00
bors b60a155515 Auto merge of #13804 - epage:underscore, r=weihanglo
fix(toml): Remove underscore field support in 2024

### What does this PR try to resolve?

This is part of the 2024 Edition and is part of rust-lang/rust#123754 and #13629

### How should we test and review this PR?

### Additional information
2024-04-26 16:37:29 +00:00
Ed Page 8ab7683f93 refactor(fix): Be consistent in fix tracking 2024-04-26 10:57:50 -05:00
Ed Page 57b4ab90a6 refactor(toml): Consolidate field name conversion 2024-04-26 10:53:28 -05:00
bors 1dadee6d8b Auto merge of #13808 - weihanglo:buildscript-msrv, r=epage
fix: emit 1.77 syntax error only when msrv is incompatible
2024-04-26 13:49:34 +00:00
Weihang Lo ba5ec686f9
fix: emit 1.77 syntax error only when msrv is incompatible 2024-04-26 09:30:26 -04:00
Weihang Lo f70bfd3f4a
test: emit 1.77 syntax error only when msrv is incompatible 2024-04-26 09:01:56 -04:00
bors e91b58d252 Auto merge of #13794 - epage:workspace, r=weihanglo
docs(ref): Index differences between virtual / real manifests

### What does this PR try to resolve?

For a user to read the reference and to understand when each type of workspace might be right for them, they have to know to also read the section on Package Selection.

This reframes the section on needing to set `resolver = "2"` to being about differences when there isn't a root package and extends it to summarize a part of Package Selection, linking out to it. The hope is that this will make it all of the differences more discoverable without retreading too much of the same ground within Reference-style documentation.

Part of #13580

### How should we test and review this PR?

### Additional information

r? `@weihanglo`
2024-04-25 22:21:37 +00:00
Ed Page 5f5e0fc504 docs(ref): Index differences between virtual / real manifests
For a user to read the reference and to understand when each type of
workspace might be right for them, they have to know to also read the
section on Package Selection.

This reframes the section on needing to set `resolver = "2"` to being
about differences when there isn't a root package and extends it to
summarize a part of Package Selection, linking out to it.
The hope is that this will make it all of the differences more
discoverable without retreading too much of the same ground within
Reference-style documentation.

Part of #13580
2024-04-25 14:33:39 -05:00
Ed Page 50adf47c18 docs(ref): Add a caution about default-members with root package 2024-04-25 14:31:49 -05:00
Ed Page 2289026d70 docs(ref): Move default-members defalting to default-members
This also tweaks the wording to be clear that `default-members` always
apply in the workspace root, not just for virtual workspaces.
2024-04-25 14:31:27 -05:00
Ed Page 58415ff288 docs(ref): Clarify default-members and members relationship
The old statement that its a subset of `members` is incorrect because
some members can be inferred and not show up in `members`.

I tried to reword this to better convey the goal of what was being said
2024-04-25 14:27:37 -05:00
Ed Page 0b15bef075 docs(ref): Simplify default-members wording
This will make it easier to make future changes
2024-04-25 14:10:38 -05:00
Ed Page 6a213f792e docs(ref): Don't call out default-members is optional
Nothing else in the files does despite it all being optional and this
will be clearer in a follow up when I specify the defaults.
2024-04-25 14:09:26 -05:00
Ed Page a71b8fecf3 feat(fix): Migrate underscore toml fields 2024-04-25 13:22:06 -05:00
bors cb1123f4f2 Auto merge of #13802 - weihanglo:refactor, r=epage
refactor(toml): extract dependency-to-source-id to function
2024-04-25 17:51:14 +00:00
Ed Page bcf032e5be test(fix): Show underscore field migration 2024-04-25 12:44:53 -05:00
Weihang Lo d855cd634a
refactor(toml): remove unnecessary `?` operators 2024-04-25 13:27:58 -04:00
Weihang Lo 7ed7612a79
refactor(toml): format arg captures 2024-04-25 13:27:58 -04:00
Weihang Lo 4b0fac9c05
refactor(toml): make match patterns explicit 2024-04-25 13:27:57 -04:00
Weihang Lo cc7fcaf57c
refactor(toml): move git and patch conflict to separate match arm 2024-04-25 13:27:57 -04:00
Weihang Lo 3505b05792
refactor(toml): show name with underscore for readability 2024-04-25 13:27:57 -04:00
Weihang Lo a5d2a1d3dc
refactor(toml): extract dependency-to-source-id to function 2024-04-25 13:27:57 -04:00
bors 93edfb9206 Auto merge of #13801 - Muscraft:add-lint-reason, r=epage
Add where lint was set

`rustc` and `clippy` both show why the lint was emitted and where the level was set the first time it was emitted for a package. We already showed why the list was being emitted but did not show where the lint level was set. This PR adds where the lint was set at.
2024-04-25 17:22:07 +00:00
Ed Page aecb40baac fix(toml): Remove underscore field support in 2024
This is part of the 2024 Edition and is part of rust-lang/rust#123754 and #13629
2024-04-25 11:56:32 -05:00
Scott Schafer dfc9bd2068
feat(lints): Add where lint level was set 2024-04-24 14:57:36 -06:00
Scott Schafer d5bc35d844
refactor(lints): Keep workspace and package lints separate 2024-04-24 14:52:45 -06:00
Scott Schafer 2655b069c6
test(cargo-lints): Add a test for workspace inheritance 2024-04-24 14:48:48 -06:00
Scott Schafer b83c0a4939
refactor(cargo-lints): Cleanup getting the level for a lint 2024-04-24 14:48:38 -06:00
bors 955503e1de Auto merge of #13800 - epage:u3, r=weihanglo
fix(toml): Don't double-warn when underscore is used in workspace dep

### What does this PR try to resolve?

This is prep for removing them in the 2024 Edition and is part of rust-lang/rust#123754 and #13629

Particularly, I wanted to make sure I didn't make things worse and in doing so found there was room for improvement.

### How should we test and review this PR?

### Additional information
2024-04-24 20:25:10 +00:00
bors e3d42b6019 Auto merge of #13798 - epage:underscore, r=weihanglo
fix(toml): Be more forceful with underscore/dash redundancy

### What does this PR try to resolve?

This is prep for removing them in the 2024 Edition and is part of rust-lang/rust#123754 and #13629

During #13783, I had considered making the 2024 edition behavior a "unused key" warning.  However, the work and code mess to pipe the data through correctly handle the two fields in all cases didn't seem worth it (and a hard error might be better to help users transition).

### How should we test and review this PR?

### Additional information
2024-04-24 19:55:43 +00:00
Ed Page 751fd47d34 fix(toml): Don't double-warn when underscore is used in workspace dep 2024-04-24 14:22:23 -05:00
Ed Page 4cc82833bd test(toml): Show default_features warning for workspace dependencies 2024-04-24 13:51:31 -05:00
Ed Page b81f94a8e9 refactor(toml): Move underscore validation to resolving 2024-04-24 13:32:04 -05:00
bors 52dae0c1f6 Auto merge of #13793 - ijackson:symlink, r=epage
Fix warning suppression for config.toml vs config compat symlinks

### What does this PR try to resolve?

Background: the cargo config file is being renamed from `.cargo/config` to `.cargo/config.toml`.  There's code in new cargo to look for both files (for compatibility), to issue a warning when onliy the old filename is found, and also to issue a warning if both files are found.  The warning suggests making a symlink if compatibility with old cargo is wanted.

An attempt was made to detect when both the old and new files exists, but one is a symlink to the other, but as reported in #13667, this code is not effective.  (It would work only if the symlink had the precise absolute pathname that cargo has decided to use for the lookup, which would be an unnatural way to make the link.)

Logically, the warning should appear when both files exist *but are different*.  That is the anomalous situation that will generate confusing behaviour.   By "different" we ought to mean "aren't the very same file".

That's what this MR implements, where possible.  On Unix, we use the information from stat(2).  That's not available on other platforms; on those, we arrange to also tolerate a symlink referring to precisely `config.toml` as a relative pathname, which is also fine, since by definition the target is then in the same directrory as `config`.

Fixes #13667.

### How should we test and review this PR?

I have interleaved the new tests with the commits that support them.  In each case, a functional commit is followed by a test which fails just beforehand.

(This can be observed by experimentally reordering the branch.)

I have also done ad-hoc testing.

### Additional information

I'm making the assumption that a symlink containing a relative path does something sane on Windows.  This assumption may be unwarranted.  If so, "Handle `config` -> `config.toml` (without full path)" needs to be dropped, and the test case needs to be `#[cfg(unix)]`.

But also, in this case, we should probably put some warnings in the stdlib docs!
2024-04-24 17:36:34 +00:00
bors 70fb498994 Auto merge of #13797 - Muscraft:cleanup-linting-system, r=epage
Cleanup linting system

There are a number of problems with the current linting system, most notably that lints could run without `-Zcargo-lints` being set. This PR fixes that issue and a few others that are low-hanging fruit.
2024-04-24 16:31:40 +00:00
Ian Jackson 2f16838385 config reading: use same_file for suppressing "both files" warning (fmt)
Apply deferred indentation changes.  Whitespace change only.
2024-04-24 15:28:09 +01:00
Ian Jackson 23440c0dcd config reading: use same_file for suppressing "both files" warning
This is 100% reliable on Unix, and better on Windows.

(In this commit I avoid reindenting things to make review easier; the
formatting will be fixed in the next commit.)

Fixes #13667
2024-04-24 15:28:08 +01:00
Ian Jackson 91f3e457ab Tests: Add test case for config.toml -> config 2024-04-24 11:45:58 +01:00
Ian Jackson dcce00745d Tests: Add test case for config -> config.toml (relative) 2024-04-24 10:12:13 +01:00
Ian Jackson 13be0cfa8b Tests: Rename config symlink creation function
"symlink A to B" is confusing; it is ambiguous (at leaset to me)
whether it means A -> B or B -> A.

And I'm about to introduce a function that does the reverse,
and also one that makes a relative rather than full path link.

So rename this function.
2024-04-24 10:03:40 +01:00
bors c939267591 Auto merge of #13790 - epage:install, r=weihanglo
fix(install): Don't respect MSRV for non-local installs

### What does this PR try to resolve?

This is part of #9930

### How should we test and review this PR?

### Additional information
2024-04-23 19:35:19 +00:00
Ed Page dcbf2b5d32 fix(install): Don't respect MSRV for non-local installs
This is part of #9930
2024-04-23 14:17:10 -05:00
Ed Page cd8d5f7c10 refactor(msrv): Simplify tracking of use of MSRV-aware resolver
The design for this stems from
- It being unclear what the initialization order would be
- Prematurely writing this for `Cargo.lock` version to leverage it and
  maybe to switch other MSRV-aware logic to
2024-04-23 14:15:59 -05:00
bors 125aa57ad2 Auto merge of #13782 - klensy:llibc, r=weihanglo
gate some libc usages under cfg(unix), drop os_info features

Places few `libc` usages under `cfg(unix)`. That didn't remove it from tree, but still looks cleaner.
Drop features from os_info crate, as serde support currently unused.
2024-04-23 17:32:32 +00:00
bors b89b81a6c7 Auto merge of #13785 - epage:msrv-edition2024, r=weihanglo
feat(resolver): Add default Edition2024 to resolver v3

### What does this PR try to resolve?

With #13776 done, we can now make MSRV-aware resolver the default for the new edition as part of #9930

### How should we test and review this PR?

### Additional information
2024-04-23 02:27:06 +00:00
bors 11d5b73b29 Auto merge of #13789 - cuviper:test-offline, r=weihanglo
Fix 2 tests for offline execution

In `alt_registry::warn_for_unused_fields`, the second part of the test
runs on `--registry crates-io`, so it needs a local replacement url.

In `install::install_global_cargo_config`, it was adding to the "config"
file, but the `pkg` before it configured the dummy registry replacement
in "config.toml". So that replacement wasn't actually used, and if you
ran tests online it was trying to install `bar v0.1.1` from the real
registry! The filename is now fixed, and the test double-checks that
we're only trying to install the local `bar v0.0.1`.
2024-04-23 01:57:56 +00:00
Josh Stone 6dda4e006b Fix 2 tests for offline execution
In `alt_registry::warn_for_unused_fields`, the second part of the test
runs on `--registry crates-io`, so it needs a local replacement url.

In `install::install_global_cargo_config`, it was adding to the "config"
file, but the `pkg` before it configured the dummy registry replacement
in "config.toml". So that replacement wasn't actually used, and if you
ran tests online it was trying to install `bar v0.1.1` from the real
registry! The filename is now fixed, and the test double-checks that
we're only trying to install the local `bar v0.0.1`.
2024-04-22 16:19:17 -07:00
Ed Page 034ef3c27b fix(toml): Be more forceful with underscore/dash redundancy
During #13783, I had considered making the 2024 edition behavior a
"unused key" warning.  However, I'm being too lazy in piping the data
through correctly (and a hard error might be better to help users
transition).
2024-04-22 12:47:43 -05:00
Ed Page 9ee41598e8 feat(resolver): Add default Edition2024 to resolver v3 2024-04-22 10:45:59 -05:00
Ed Page 706f8a71c8 fix(msrv): Don't require -Zmsrv-policy for resolver=3
We still have `edition2024` guarding this.

Dealing with two feature flags to control behavior is messy.  We just
need to make sure both get stabilized :).
2024-04-22 10:45:19 -05:00
Scott Schafer 11d6013c1d
fix(cargo-lints): Respect Forbid lint level 2024-04-20 20:12:47 -06:00
Scott Schafer 2d40a475d9
feat: Add unstable im_a_teapot lint 2024-04-20 19:33:13 -06:00
Scott Schafer 00a64e4da3
fix: Only run lints when cargo-lints are enabled 2024-04-20 19:22:32 -06:00
Scott Schafer b89864cc3b
fix: Allow should not get translated to Note 2024-04-20 16:31:04 -06:00
klensy 57e820e329 cargo-credential: bump version to 0.4.5
as required by check-version-bump CI
2024-04-20 10:38:49 +03:00
klensy ef39fbf231 os_info: use default-features = false, as no serde support needed 2024-04-19 15:49:19 +03:00
klensy 3215929365 gate some libc usages under cfg(unix) 2024-04-19 15:27:21 +03:00
34 changed files with 1649 additions and 393 deletions

3
Cargo.lock generated
View File

@ -350,7 +350,7 @@ dependencies = [
[[package]]
name = "cargo-credential"
version = "0.4.4"
version = "0.4.5"
dependencies = [
"anyhow",
"libc",
@ -2481,7 +2481,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
dependencies = [
"log",
"serde",
"windows-sys 0.52.0",
]

View File

@ -68,7 +68,7 @@ miow = "0.6.0"
opener = "0.7.0"
openssl = "0.10.57"
openssl-sys = "=0.9.92" # See rust-lang/cargo#13546 and openssl/openssl#23376 for pinning
os_info = "3.8.2"
os_info = { version = "3.8.2", default-features = false }
pasetors = { version = "0.6.8", features = ["v3", "paserk", "std", "serde"] }
pathdiff = "0.2"
percent-encoding = "2.3"
@ -173,7 +173,6 @@ indexmap.workspace = true
itertools.workspace = true
jobserver.workspace = true
lazycell.workspace = true
libc.workspace = true
libgit2-sys.workspace = true
memchr.workspace = true
opener.workspace = true
@ -184,6 +183,7 @@ rand.workspace = true
regex.workspace = true
rusqlite.workspace = true
rustfix.workspace = true
same-file.workspace = true
semver.workspace = true
serde = { workspace = true, features = ["derive"] }
serde-untagged.workspace = true
@ -208,6 +208,9 @@ supports-unicode = "3.0.0"
[target.'cfg(target_has_atomic = "64")'.dependencies]
tracing-chrome.workspace = true
[target.'cfg(unix)'.dependencies]
libc.workspace = true
[target.'cfg(target_os = "linux")'.dependencies]
cargo-credential-libsecret.workspace = true

View File

@ -51,7 +51,7 @@ pub struct TomlManifest {
pub replace: Option<BTreeMap<String, TomlDependency>>,
pub patch: Option<BTreeMap<String, BTreeMap<PackageName, TomlDependency>>>,
pub workspace: Option<TomlWorkspace>,
pub badges: Option<InheritableBtreeMap>,
pub badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
pub lints: Option<InheritableLints>,
/// Report unused keys (see also nested `_unused_keys`)
@ -106,12 +106,6 @@ impl TomlManifest {
self.features.as_ref()
}
pub fn resolved_badges(
&self,
) -> Result<Option<&BTreeMap<String, BTreeMap<String, String>>>, UnresolvedError> {
self.badges.as_ref().map(|l| l.resolved()).transpose()
}
pub fn resolved_lints(&self) -> Result<Option<&TomlLints>, UnresolvedError> {
self.lints.as_ref().map(|l| l.resolved()).transpose()
}
@ -1506,7 +1500,7 @@ pub struct TomlLintConfig {
pub priority: i8,
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum TomlLintLevel {
Forbid,

View File

@ -14,7 +14,6 @@ filetime.workspace = true
hex.workspace = true
ignore.workspace = true
jobserver.workspace = true
libc.workspace = true
same-file.workspace = true
sha2.workspace = true
shell-escape.workspace = true
@ -25,6 +24,9 @@ walkdir.workspace = true
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation.workspace = true
[target.'cfg(unix)'.dependencies]
libc.workspace = true
[target.'cfg(windows)'.dependencies]
miow.workspace = true
windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem", "Win32_Foundation", "Win32_System_Console"] }

View File

@ -1,6 +1,6 @@
[package]
name = "cargo-credential"
version = "0.4.4"
version = "0.4.5"
rust-version.workspace = true
edition.workspace = true
license.workspace = true
@ -10,12 +10,14 @@ description = "A library to assist writing Cargo credential helpers."
[dependencies]
anyhow.workspace = true
libc.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror.workspace = true
time.workspace = true
[target.'cfg(unix)'.dependencies]
libc.workspace = true
[target.'cfg(windows)'.dependencies]
windows-sys = { workspace = true, features = ["Win32_System_Console", "Win32_Foundation"] }

View File

@ -72,7 +72,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
// code as we can.
let root_manifest = args.root_manifest(gctx)?;
let mut ws = Workspace::new(&root_manifest, gctx)?;
ws.set_honor_rust_version(args.honor_rust_version());
ws.set_resolve_honors_rust_version(args.honor_rust_version());
let mut opts = args.compile_options(gctx, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?;
if !opts.filter.is_specific() {

View File

@ -724,10 +724,9 @@ impl BuildOutput {
pkg_descr: &str,
msrv: &Option<RustVersion>,
) -> CargoResult<()> {
let new_syntax_added_in = &RustVersion::from_str("1.77.0")?;
if let Some(msrv) = msrv {
if msrv < new_syntax_added_in {
let new_syntax_added_in = RustVersion::from_str("1.77.0")?;
if !new_syntax_added_in.is_compatible_with(msrv.as_partial()) {
bail!(
"the `cargo::` syntax for build script output instructions was added in \
Rust 1.77.0, but the minimum supported Rust version of `{pkg_descr}` is {msrv}.\n\

View File

@ -300,7 +300,9 @@ impl Edition {
}
pub(crate) fn default_resolve_behavior(&self) -> ResolveBehavior {
if *self >= Edition::Edition2021 {
if *self >= Edition::Edition2024 {
ResolveBehavior::V3
} else if *self >= Edition::Edition2021 {
ResolveBehavior::V2
} else {
ResolveBehavior::V1

View File

@ -24,7 +24,7 @@ use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
use crate::util::edit_distance;
use crate::util::errors::{CargoResult, ManifestError};
use crate::util::interning::InternedString;
use crate::util::lints::{check_implicit_features, unused_dependencies};
use crate::util::lints::{check_im_a_teapot, check_implicit_features, unused_dependencies};
use crate::util::toml::{read_manifest, InheritableFields};
use crate::util::{
context::CargoResolverConfig, context::CargoResolverPrecedence, context::ConfigRelativePath,
@ -104,7 +104,6 @@ pub struct Workspace<'gctx> {
/// The resolver behavior specified with the `resolver` field.
resolve_behavior: ResolveBehavior,
resolve_honors_rust_version: bool,
honor_rust_version: Option<bool>,
/// Workspace-level custom metadata
custom_metadata: Option<toml::Value>,
@ -235,7 +234,6 @@ impl<'gctx> Workspace<'gctx> {
ignore_lock: false,
resolve_behavior: ResolveBehavior::V1,
resolve_honors_rust_version: false,
honor_rust_version: None,
custom_metadata: None,
}
}
@ -310,9 +308,6 @@ impl<'gctx> Workspace<'gctx> {
ResolveBehavior::V1 | ResolveBehavior::V2 => {}
ResolveBehavior::V3 => {
if self.resolve_behavior == ResolveBehavior::V3 {
if !self.gctx().cli_unstable().msrv_policy {
anyhow::bail!("`resolver=\"3\"` requires `-Zmsrv-policy`");
}
self.resolve_honors_rust_version = true;
}
}
@ -652,18 +647,14 @@ impl<'gctx> Workspace<'gctx> {
self.members().filter_map(|pkg| pkg.rust_version()).min()
}
pub fn set_honor_rust_version(&mut self, honor_rust_version: Option<bool>) {
self.honor_rust_version = honor_rust_version;
}
pub fn honor_rust_version(&self) -> Option<bool> {
self.honor_rust_version
pub fn set_resolve_honors_rust_version(&mut self, honor_rust_version: Option<bool>) {
if let Some(honor_rust_version) = honor_rust_version {
self.resolve_honors_rust_version = honor_rust_version;
}
}
pub fn resolve_honors_rust_version(&self) -> bool {
// Give CLI precedence
self.honor_rust_version
.unwrap_or(self.resolve_honors_rust_version)
self.resolve_honors_rust_version
}
pub fn custom_metadata(&self) -> Option<&toml::Value> {
@ -1156,10 +1147,27 @@ impl<'gctx> Workspace<'gctx> {
}
pub fn emit_warnings(&self) -> CargoResult<()> {
let ws_lints = self
.root_maybe()
.workspace_config()
.inheritable()
.and_then(|i| i.lints().ok())
.unwrap_or_default();
let ws_cargo_lints = ws_lints
.get("cargo")
.cloned()
.unwrap_or_default()
.into_iter()
.map(|(k, v)| (k.replace('-', "_"), v))
.collect();
for (path, maybe_pkg) in &self.packages.packages {
let path = path.join("Cargo.toml");
if let MaybePackage::Package(pkg) = maybe_pkg {
self.emit_lints(pkg, &path)?
if self.gctx.cli_unstable().cargo_lints {
self.emit_lints(pkg, &path, &ws_cargo_lints)?
}
}
let warnings = match maybe_pkg {
MaybePackage::Package(pkg) => pkg.manifest().warnings().warnings(),
@ -1186,7 +1194,12 @@ impl<'gctx> Workspace<'gctx> {
Ok(())
}
pub fn emit_lints(&self, pkg: &Package, path: &Path) -> CargoResult<()> {
pub fn emit_lints(
&self,
pkg: &Package,
path: &Path,
ws_cargo_lints: &manifest::TomlToolLints,
) -> CargoResult<()> {
let mut error_count = 0;
let toml_lints = pkg
.manifest()
@ -1204,8 +1217,40 @@ impl<'gctx> Workspace<'gctx> {
.map(|(name, lint)| (name.replace('-', "_"), lint))
.collect();
check_implicit_features(pkg, &path, &normalized_lints, &mut error_count, self.gctx)?;
unused_dependencies(pkg, &path, &normalized_lints, &mut error_count, self.gctx)?;
// We should only be using workspace lints if the `[lints]` table is
// present in the manifest, and `workspace` is set to `true`
let ws_cargo_lints = pkg
.manifest()
.resolved_toml()
.lints
.as_ref()
.is_some_and(|l| l.workspace)
.then(|| ws_cargo_lints);
check_im_a_teapot(
pkg,
&path,
&normalized_lints,
ws_cargo_lints,
&mut error_count,
self.gctx,
)?;
check_implicit_features(
pkg,
&path,
&normalized_lints,
ws_cargo_lints,
&mut error_count,
self.gctx,
)?;
unused_dependencies(
pkg,
&path,
&normalized_lints,
ws_cargo_lints,
&mut error_count,
self.gctx,
)?;
if error_count > 0 {
Err(crate::util::errors::AlreadyPrintedError::new(anyhow!(
"encountered {error_count} errors(s) while running lints"

View File

@ -819,7 +819,9 @@ fn make_ws_rustc_target<'gctx>(
let mut ws = if source_id.is_git() || source_id.is_path() {
Workspace::new(pkg.manifest_path(), gctx)?
} else {
Workspace::ephemeral(pkg, gctx, None, false)?
let mut ws = Workspace::ephemeral(pkg, gctx, None, false)?;
ws.set_resolve_honors_rust_version(Some(false));
ws
};
ws.set_ignore_lock(gctx.lock_update_allowed());
ws.set_require_optional_deps(false);

View File

@ -108,7 +108,7 @@ pub fn fix(
check_resolver_change(&original_ws, opts)?;
}
let mut ws = Workspace::new(&root_manifest, gctx)?;
ws.set_honor_rust_version(original_ws.honor_rust_version());
ws.set_resolve_honors_rust_version(Some(original_ws.resolve_honors_rust_version()));
// Spin up our lock server, which our subprocesses will use to synchronize fixes.
let lock_server = LockServer::new()?;
@ -254,9 +254,42 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
let mut fixes = 0;
let root = document.as_table_mut();
if let Some(workspace) = root
.get_mut("workspace")
.and_then(|t| t.as_table_like_mut())
{
// strictly speaking, the edition doesn't apply to this table but it should be safe
// enough
fixes += rename_dep_fields_2024(workspace, "dependencies");
}
fixes += add_feature_for_unused_deps(pkg, root);
if rename_table(root, "project", "package") {
fixes += 1;
fixes += rename_table(root, "project", "package");
if let Some(target) = root.get_mut("lib").and_then(|t| t.as_table_like_mut()) {
fixes += rename_target_fields_2024(target);
}
fixes += rename_array_of_target_fields_2024(root, "bin");
fixes += rename_array_of_target_fields_2024(root, "example");
fixes += rename_array_of_target_fields_2024(root, "test");
fixes += rename_array_of_target_fields_2024(root, "bench");
fixes += rename_dep_fields_2024(root, "dependencies");
fixes += rename_table(root, "dev_dependencies", "dev-dependencies");
fixes += rename_dep_fields_2024(root, "dev-dependencies");
fixes += rename_table(root, "build_dependencies", "build-dependencies");
fixes += rename_dep_fields_2024(root, "build-dependencies");
for target in root
.get_mut("target")
.and_then(|t| t.as_table_like_mut())
.iter_mut()
.flat_map(|t| t.iter_mut())
.filter_map(|(_k, t)| t.as_table_like_mut())
{
fixes += rename_dep_fields_2024(target, "dependencies");
fixes += rename_table(target, "dev_dependencies", "dev-dependencies");
fixes += rename_dep_fields_2024(target, "dev-dependencies");
fixes += rename_table(target, "build_dependencies", "build-dependencies");
fixes += rename_dep_fields_2024(target, "build-dependencies");
}
if 0 < fixes {
@ -274,9 +307,43 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
Ok(())
}
fn rename_table(parent: &mut dyn toml_edit::TableLike, old: &str, new: &str) -> bool {
fn rename_dep_fields_2024(parent: &mut dyn toml_edit::TableLike, dep_kind: &str) -> usize {
let mut fixes = 0;
for target in parent
.get_mut(dep_kind)
.and_then(|t| t.as_table_like_mut())
.iter_mut()
.flat_map(|t| t.iter_mut())
.filter_map(|(_k, t)| t.as_table_like_mut())
{
fixes += rename_table(target, "default_features", "default-features");
}
fixes
}
fn rename_array_of_target_fields_2024(root: &mut dyn toml_edit::TableLike, kind: &str) -> usize {
let mut fixes = 0;
for target in root
.get_mut(kind)
.and_then(|t| t.as_array_of_tables_mut())
.iter_mut()
.flat_map(|t| t.iter_mut())
{
fixes += rename_target_fields_2024(target);
}
fixes
}
fn rename_target_fields_2024(target: &mut dyn toml_edit::TableLike) -> usize {
let mut fixes = 0;
fixes += rename_table(target, "crate_type", "crate-type");
fixes += rename_table(target, "proc_macro", "proc-macro");
fixes
}
fn rename_table(parent: &mut dyn toml_edit::TableLike, old: &str, new: &str) -> usize {
let Some(old_key) = parent.key(old).cloned() else {
return false;
return 0;
};
let project = parent.remove(old).expect("returned early");
@ -286,7 +353,7 @@ fn rename_table(parent: &mut dyn toml_edit::TableLike, old: &str, new: &str) ->
*new_key.dotted_decor_mut() = old_key.dotted_decor().clone();
*new_key.leaf_decor_mut() = old_key.leaf_decor().clone();
}
true
1
}
fn add_feature_for_unused_deps(pkg: &Package, parent: &mut dyn toml_edit::TableLike) -> usize {

View File

@ -505,7 +505,7 @@ pub trait ArgMatchesExt {
fn workspace<'a>(&self, gctx: &'a GlobalContext) -> CargoResult<Workspace<'a>> {
let root = self.root_manifest(gctx)?;
let mut ws = Workspace::new(&root, gctx)?;
ws.set_honor_rust_version(self.honor_rust_version());
ws.set_resolve_honors_rust_version(self.honor_rust_version());
if gctx.cli_unstable().avoid_dev_deps {
ws.set_require_optional_deps(false);
}

View File

@ -1537,36 +1537,32 @@ impl GlobalContext {
let possible = dir.join(filename_without_extension);
let possible_with_extension = dir.join(format!("{}.toml", filename_without_extension));
if possible.exists() {
if let Ok(possible_handle) = same_file::Handle::from_path(&possible) {
if warn {
// We don't want to print a warning if the version
// without the extension is just a symlink to the version
// WITH an extension, which people may want to do to
// support multiple Cargo versions at once and not
// get a warning.
let skip_warning = if let Ok(target_path) = fs::read_link(&possible) {
target_path == possible_with_extension
} else {
false
};
if !skip_warning {
if possible_with_extension.exists() {
if let Ok(possible_with_extension_handle) =
same_file::Handle::from_path(&possible_with_extension)
{
// We don't want to print a warning if the version
// without the extension is just a symlink to the version
// WITH an extension, which people may want to do to
// support multiple Cargo versions at once and not
// get a warning.
if possible_handle != possible_with_extension_handle {
self.shell().warn(format!(
"both `{}` and `{}` exist. Using `{}`",
possible.display(),
possible_with_extension.display(),
possible.display()
))?;
} else {
self.shell().warn(format!(
"`{}` is deprecated in favor of `{filename_without_extension}.toml`",
possible.display(),
))?;
self.shell().note(
format!("if you need to support cargo 1.38 or earlier, you can symlink `{filename_without_extension}` to `{filename_without_extension}.toml`"),
)?;
}
} else {
self.shell().warn(format!(
"`{}` is deprecated in favor of `{filename_without_extension}.toml`",
possible.display(),
))?;
self.shell().note(
format!("if you need to support cargo 1.38 or earlier, you can symlink `{filename_without_extension}` to `{filename_without_extension}.toml`"),
)?;
}
}

View File

@ -68,6 +68,13 @@ pub struct LintGroup {
pub edition_lint_opts: Option<(Edition, LintLevel)>,
}
const TEST_DUMMY_UNSTABLE: LintGroup = LintGroup {
name: "test_dummy_unstable",
desc: "test_dummy_unstable is meant to only be used in tests",
default_level: LintLevel::Allow,
edition_lint_opts: None,
};
#[derive(Copy, Clone, Debug)]
pub struct Lint {
pub name: &'static str,
@ -78,26 +85,41 @@ pub struct Lint {
}
impl Lint {
pub fn level(&self, lints: &TomlToolLints, edition: Edition) -> LintLevel {
let level = self
.groups
pub fn level(
&self,
pkg_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
edition: Edition,
) -> (LintLevel, LintLevelReason) {
self.groups
.iter()
.map(|g| g.name)
.chain(std::iter::once(self.name))
.filter_map(|n| lints.get(n).map(|l| (n, l)))
.max_by_key(|(n, l)| (l.priority(), std::cmp::Reverse(*n)));
match level {
Some((_, toml_lint)) => toml_lint.level().into(),
None => {
if let Some((lint_edition, lint_level)) = self.edition_lint_opts {
if edition >= lint_edition {
return lint_level;
}
}
self.default_level
}
}
.map(|g| {
(
g.name,
level_priority(
g.name,
g.default_level,
g.edition_lint_opts,
pkg_lints,
ws_lints,
edition,
),
)
})
.chain(std::iter::once((
self.name,
level_priority(
self.name,
self.default_level,
self.edition_lint_opts,
pkg_lints,
ws_lints,
edition,
),
)))
.max_by_key(|(n, (l, _, p))| (l == &LintLevel::Forbid, *p, std::cmp::Reverse(*n)))
.map(|(_, (l, r, _))| (l, r))
.unwrap()
}
}
@ -123,7 +145,7 @@ impl Display for LintLevel {
impl LintLevel {
pub fn to_diagnostic_level(self) -> Level {
match self {
LintLevel::Allow => Level::Note,
LintLevel::Allow => unreachable!("allow does not map to a diagnostic level"),
LintLevel::Warn => Level::Warning,
LintLevel::Deny => Level::Error,
LintLevel::Forbid => Level::Error,
@ -142,6 +164,123 @@ impl From<TomlLintLevel> for LintLevel {
}
}
#[derive(Copy, Clone, Debug)]
pub enum LintLevelReason {
Default,
Edition(Edition),
Package,
Workspace,
}
impl Display for LintLevelReason {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LintLevelReason::Default => write!(f, "by default"),
LintLevelReason::Edition(edition) => write!(f, "in edition {}", edition),
LintLevelReason::Package => write!(f, "in `[lints]`"),
LintLevelReason::Workspace => write!(f, "in `[workspace.lints]`"),
}
}
}
fn level_priority(
name: &str,
default_level: LintLevel,
edition_lint_opts: Option<(Edition, LintLevel)>,
pkg_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
edition: Edition,
) -> (LintLevel, LintLevelReason, i8) {
let (unspecified_level, reason) = if let Some(level) = edition_lint_opts
.filter(|(e, _)| edition >= *e)
.map(|(_, l)| l)
{
(level, LintLevelReason::Edition(edition))
} else {
(default_level, LintLevelReason::Default)
};
// Don't allow the group to be overridden if the level is `Forbid`
if unspecified_level == LintLevel::Forbid {
return (unspecified_level, reason, 0);
}
if let Some(defined_level) = pkg_lints.get(name) {
(
defined_level.level().into(),
LintLevelReason::Package,
defined_level.priority(),
)
} else if let Some(defined_level) = ws_lints.and_then(|l| l.get(name)) {
(
defined_level.level().into(),
LintLevelReason::Workspace,
defined_level.priority(),
)
} else {
(unspecified_level, reason, 0)
}
}
const IM_A_TEAPOT: Lint = Lint {
name: "im_a_teapot",
desc: "`im_a_teapot` is specified",
groups: &[TEST_DUMMY_UNSTABLE],
default_level: LintLevel::Allow,
edition_lint_opts: None,
};
pub fn check_im_a_teapot(
pkg: &Package,
path: &Path,
pkg_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
error_count: &mut usize,
gctx: &GlobalContext,
) -> CargoResult<()> {
let manifest = pkg.manifest();
let (lint_level, reason) = IM_A_TEAPOT.level(pkg_lints, ws_lints, manifest.edition());
if lint_level == LintLevel::Allow {
return Ok(());
}
if manifest
.resolved_toml()
.package()
.is_some_and(|p| p.im_a_teapot.is_some())
{
if lint_level == LintLevel::Forbid || lint_level == LintLevel::Deny {
*error_count += 1;
}
let level = lint_level.to_diagnostic_level();
let manifest_path = rel_cwd_manifest_path(path, gctx);
let emitted_reason = format!(
"`cargo::{}` is set to `{lint_level}` {reason}",
IM_A_TEAPOT.name
);
let key_span = get_span(manifest.document(), &["package", "im-a-teapot"], false).unwrap();
let value_span = get_span(manifest.document(), &["package", "im-a-teapot"], true).unwrap();
let message = level
.title(IM_A_TEAPOT.desc)
.snippet(
Snippet::source(manifest.contents())
.origin(&manifest_path)
.annotation(level.span(key_span.start..value_span.end))
.fold(true),
)
.footer(Level::Note.title(&emitted_reason));
let renderer = Renderer::styled().term_width(
gctx.shell()
.err_width()
.diagnostic_terminal_width()
.unwrap_or(annotate_snippets::renderer::DEFAULT_TERM_WIDTH),
);
writeln!(gctx.shell().err(), "{}", renderer.render(message))?;
}
Ok(())
}
/// By default, cargo will treat any optional dependency as a [feature]. As of
/// cargo 1.60, these can be disabled by declaring a feature that activates the
/// optional dependency as `dep:<name>` (see [RFC #3143]).
@ -166,7 +305,8 @@ const IMPLICIT_FEATURES: Lint = Lint {
pub fn check_implicit_features(
pkg: &Package,
path: &Path,
lints: &TomlToolLints,
pkg_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
error_count: &mut usize,
gctx: &GlobalContext,
) -> CargoResult<()> {
@ -177,7 +317,7 @@ pub fn check_implicit_features(
return Ok(());
}
let lint_level = IMPLICIT_FEATURES.level(lints, edition);
let (lint_level, reason) = IMPLICIT_FEATURES.level(pkg_lints, ws_lints, edition);
if lint_level == LintLevel::Allow {
return Ok(());
}
@ -222,7 +362,7 @@ pub fn check_implicit_features(
);
if emitted_source.is_none() {
emitted_source = Some(format!(
"`cargo::{}` is set to `{lint_level}`",
"`cargo::{}` is set to `{lint_level}` {reason}",
IMPLICIT_FEATURES.name
));
message = message.footer(Level::Note.title(emitted_source.as_ref().unwrap()));
@ -249,7 +389,8 @@ const UNUSED_OPTIONAL_DEPENDENCY: Lint = Lint {
pub fn unused_dependencies(
pkg: &Package,
path: &Path,
lints: &TomlToolLints,
pkg_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
error_count: &mut usize,
gctx: &GlobalContext,
) -> CargoResult<()> {
@ -259,7 +400,7 @@ pub fn unused_dependencies(
return Ok(());
}
let lint_level = UNUSED_OPTIONAL_DEPENDENCY.level(lints, edition);
let (lint_level, reason) = UNUSED_OPTIONAL_DEPENDENCY.level(pkg_lints, ws_lints, edition);
if lint_level == LintLevel::Allow {
return Ok(());
}
@ -325,7 +466,7 @@ pub fn unused_dependencies(
);
if emitted_source.is_none() {
emitted_source = Some(format!(
"`cargo::{}` is set to `{lint_level}`",
"`cargo::{}` is set to `{lint_level}` {reason}",
UNUSED_OPTIONAL_DEPENDENCY.name
));
message =

View File

@ -90,13 +90,15 @@ impl<T> SleepTracker<T> {
#[test]
fn returns_in_order() {
let mut s = SleepTracker::new();
s.push(3, 3);
s.push(30_000, 30_000);
s.push(1, 1);
s.push(6, 6);
s.push(5, 5);
s.push(2, 2);
s.push(10000, 10000);
assert_eq!(s.len(), 6);
std::thread::sleep(Duration::from_millis(100));
assert_eq!(s.to_retry(), &[1, 2, 3, 5, 6]);
assert_eq!(s.len(), 2);
std::thread::sleep(Duration::from_millis(2));
assert_eq!(s.to_retry(), &[1]);
assert!(s.to_retry().is_empty());
let next = s.time_to_next().expect("should be next");
assert!(
next < Duration::from_millis(30_000),
"{next:?} should be less than 30s"
);
}

View File

@ -306,6 +306,8 @@ fn resolve_toml(
};
if let Some(original_package) = original_toml.package() {
let package_name = &original_package.name;
let resolved_package =
resolve_package_toml(original_package, features, package_root, &inherit)?;
let edition = resolved_package
@ -341,6 +343,15 @@ fn resolve_toml(
package_root,
warnings,
)?;
deprecated_underscore(
&original_toml.dev_dependencies2,
&original_toml.dev_dependencies,
"dev-dependencies",
package_name,
"package",
edition,
warnings,
)?;
resolved_toml.dev_dependencies = resolve_dependencies(
gctx,
edition,
@ -352,6 +363,15 @@ fn resolve_toml(
package_root,
warnings,
)?;
deprecated_underscore(
&original_toml.build_dependencies2,
&original_toml.build_dependencies,
"build-dependencies",
package_name,
"package",
edition,
warnings,
)?;
resolved_toml.build_dependencies = resolve_dependencies(
gctx,
edition,
@ -376,6 +396,15 @@ fn resolve_toml(
package_root,
warnings,
)?;
deprecated_underscore(
&platform.dev_dependencies2,
&platform.dev_dependencies,
"dev-dependencies",
name,
"platform target",
edition,
warnings,
)?;
let resolved_dev_dependencies = resolve_dependencies(
gctx,
edition,
@ -387,6 +416,15 @@ fn resolve_toml(
package_root,
warnings,
)?;
deprecated_underscore(
&platform.build_dependencies2,
&platform.build_dependencies,
"build-dependencies",
name,
"platform target",
edition,
warnings,
)?;
let resolved_build_dependencies = resolve_dependencies(
gctx,
edition,
@ -411,22 +449,9 @@ fn resolve_toml(
}
resolved_toml.target = (!resolved_target.is_empty()).then_some(resolved_target);
let resolved_lints = original_toml
.lints
.clone()
.map(|value| lints_inherit_with(value, || inherit()?.lints()))
.transpose()?;
resolved_toml.lints = resolved_lints.map(|lints| manifest::InheritableLints {
workspace: false,
lints,
});
resolved_toml.lints = original_toml.lints.clone();
let resolved_badges = original_toml
.badges
.clone()
.map(|mw| field_inherit_with(mw, "badges", || inherit()?.badges()))
.transpose()?;
resolved_toml.badges = resolved_badges.map(manifest::InheritableField::Value);
resolved_toml.badges = original_toml.badges.clone();
} else {
for field in original_toml.requires_package() {
bail!("this virtual manifest specifies a `{field}` section, which is not allowed");
@ -625,6 +650,15 @@ fn resolve_dependencies<'a>(
let mut resolved =
dependency_inherit_with(v.clone(), name_in_toml, inherit, package_root, warnings)?;
if let manifest::TomlDependency::Detailed(ref mut d) = resolved {
deprecated_underscore(
&d.default_features2,
&d.default_features,
"default-features",
name_in_toml,
"dependency",
edition,
warnings,
)?;
if d.public.is_some() {
let public_feature = features.require(Feature::public_dependency());
let with_public_feature = public_feature.is_ok();
@ -760,7 +794,6 @@ impl InheritableFields {
package_field_getter! {
// Please keep this list lexicographically ordered.
("authors", authors -> Vec<String>),
("badges", badges -> BTreeMap<String, BTreeMap<String, String>>),
("categories", categories -> Vec<String>),
("description", description -> String),
("documentation", documentation -> String),
@ -803,7 +836,7 @@ impl InheritableFields {
}
/// Gets the field `workspace.lint`.
fn lints(&self) -> CargoResult<manifest::TomlLints> {
pub fn lints(&self) -> CargoResult<manifest::TomlLints> {
let Some(val) = &self.lints else {
bail!("`workspace.lints` was not defined");
};
@ -904,14 +937,6 @@ fn inner_dependency_inherit_with<'a>(
this could become a hard error in the future"
))
}
deprecated_underscore(
&dependency.default_features2,
&dependency.default_features,
"default-features",
name,
"dependency",
warnings,
);
inherit()?.get_dependency(name, package_root).map(|d| {
match d {
manifest::TomlDependency::Simple(s) => {
@ -1162,28 +1187,12 @@ fn to_real_manifest(
}
validate_dependencies(original_toml.dependencies.as_ref(), None, None, warnings)?;
deprecated_underscore(
&original_toml.dev_dependencies2,
&original_toml.dev_dependencies,
"dev-dependencies",
package_name,
"package",
warnings,
);
validate_dependencies(
original_toml.dev_dependencies(),
None,
Some(DepKind::Development),
warnings,
)?;
deprecated_underscore(
&original_toml.build_dependencies2,
&original_toml.build_dependencies,
"build-dependencies",
package_name,
"package",
warnings,
);
validate_dependencies(
original_toml.build_dependencies(),
None,
@ -1200,28 +1209,12 @@ fn to_real_manifest(
None,
warnings,
)?;
deprecated_underscore(
&platform.build_dependencies2,
&platform.build_dependencies,
"build-dependencies",
name,
"platform target",
warnings,
);
validate_dependencies(
platform.build_dependencies(),
platform_kind.as_ref(),
Some(DepKind::Build),
warnings,
)?;
deprecated_underscore(
&platform.dev_dependencies2,
&platform.dev_dependencies,
"dev-dependencies",
name,
"platform target",
warnings,
);
validate_dependencies(
platform.dev_dependencies(),
platform_kind.as_ref(),
@ -1284,18 +1277,18 @@ fn to_real_manifest(
}
}
verify_lints(
resolved_toml.resolved_lints().expect("previously resolved"),
gctx,
warnings,
)?;
let default = manifest::TomlLints::default();
let rustflags = lints_to_rustflags(
resolved_toml
.resolved_lints()
.expect("previously resolved")
.unwrap_or(&default),
);
let resolved_lints = resolved_toml
.lints
.clone()
.map(|value| {
lints_inherit_with(value, || {
load_inheritable_fields(gctx, manifest_file, &workspace_config)?.lints()
})
})
.transpose()?;
verify_lints(resolved_lints.as_ref(), gctx, warnings)?;
let rustflags = lints_to_rustflags(&resolved_lints.unwrap_or_default());
let metadata = ManifestMetadata {
description: resolved_package
@ -1341,11 +1334,7 @@ fn to_real_manifest(
.expect("previously resolved")
.cloned()
.unwrap_or_default(),
badges: resolved_toml
.resolved_badges()
.expect("previously resolved")
.cloned()
.unwrap_or_default(),
badges: resolved_toml.badges.clone().unwrap_or_default(),
links: resolved_package.links.clone(),
rust_version: rust_version.clone(),
};
@ -1818,90 +1807,7 @@ fn detailed_dep_to_dependency<P: ResolveToPath + Clone>(
}
}
let new_source_id = match (
orig.git.as_ref(),
orig.path.as_ref(),
orig.registry.as_ref(),
orig.registry_index.as_ref(),
) {
(Some(_), _, Some(_), _) | (Some(_), _, _, Some(_)) => bail!(
"dependency ({}) specification is ambiguous. \
Only one of `git` or `registry` is allowed.",
name_in_toml
),
(_, _, Some(_), Some(_)) => bail!(
"dependency ({}) specification is ambiguous. \
Only one of `registry` or `registry-index` is allowed.",
name_in_toml
),
(Some(git), maybe_path, _, _) => {
if maybe_path.is_some() {
bail!(
"dependency ({}) specification is ambiguous. \
Only one of `git` or `path` is allowed.",
name_in_toml
);
}
let n_details = [&orig.branch, &orig.tag, &orig.rev]
.iter()
.filter(|d| d.is_some())
.count();
if n_details > 1 {
bail!(
"dependency ({}) specification is ambiguous. \
Only one of `branch`, `tag` or `rev` is allowed.",
name_in_toml
);
}
let reference = orig
.branch
.clone()
.map(GitReference::Branch)
.or_else(|| orig.tag.clone().map(GitReference::Tag))
.or_else(|| orig.rev.clone().map(GitReference::Rev))
.unwrap_or(GitReference::DefaultBranch);
let loc = git.into_url()?;
if let Some(fragment) = loc.fragment() {
let msg = format!(
"URL fragment `#{}` in git URL is ignored for dependency ({}). \
If you were trying to specify a specific git revision, \
use `rev = \"{}\"` in the dependency declaration.",
fragment, name_in_toml, fragment
);
manifest_ctx.warnings.push(msg)
}
SourceId::for_git(&loc, reference)?
}
(None, Some(path), _, _) => {
let path = path.resolve(manifest_ctx.gctx);
// If the source ID for the package we're parsing is a path
// source, then we normalize the path here to get rid of
// components like `..`.
//
// The purpose of this is to get a canonical ID for the package
// that we're depending on to ensure that builds of this package
// always end up hashing to the same value no matter where it's
// built from.
if manifest_ctx.source_id.is_path() {
let path = manifest_ctx.root.join(path);
let path = paths::normalize_path(&path);
SourceId::for_path(&path)?
} else {
manifest_ctx.source_id
}
}
(None, None, Some(registry), None) => SourceId::alt_registry(manifest_ctx.gctx, registry)?,
(None, None, None, Some(registry_index)) => {
let url = registry_index.into_url()?;
SourceId::for_registry(&url)?
}
(None, None, None, None) => SourceId::crates_io(manifest_ctx.gctx)?,
};
let new_source_id = to_dependency_source_id(orig, name_in_toml, manifest_ctx)?;
let (pkg_name, explicit_name_in_toml) = match orig.package {
Some(ref s) => (&s[..], Some(name_in_toml)),
@ -1910,14 +1816,6 @@ fn detailed_dep_to_dependency<P: ResolveToPath + Clone>(
let version = orig.version.as_deref();
let mut dep = Dependency::parse(pkg_name, version, new_source_id)?;
deprecated_underscore(
&orig.default_features2,
&orig.default_features,
"default-features",
name_in_toml,
"dependency",
manifest_ctx.warnings,
);
dep.set_features(orig.features.iter().flatten())
.set_default_features(orig.default_features().unwrap_or(true))
.set_optional(orig.optional.unwrap_or(false))
@ -1980,6 +1878,91 @@ fn detailed_dep_to_dependency<P: ResolveToPath + Clone>(
Ok(dep)
}
fn to_dependency_source_id<P: ResolveToPath + Clone>(
orig: &manifest::TomlDetailedDependency<P>,
name_in_toml: &str,
manifest_ctx: &mut ManifestContext<'_, '_>,
) -> CargoResult<SourceId> {
match (
orig.git.as_ref(),
orig.path.as_ref(),
orig.registry.as_deref(),
orig.registry_index.as_ref(),
) {
(Some(_git), _, Some(_registry), _) | (Some(_git), _, _, Some(_registry)) => bail!(
"dependency ({name_in_toml}) specification is ambiguous. \
Only one of `git` or `registry` is allowed.",
),
(_, _, Some(_registry), Some(_registry_index)) => bail!(
"dependency ({name_in_toml}) specification is ambiguous. \
Only one of `registry` or `registry-index` is allowed.",
),
(Some(_git), Some(_path), None, None) => {
bail!(
"dependency ({name_in_toml}) specification is ambiguous. \
Only one of `git` or `path` is allowed.",
);
}
(Some(git), None, None, None) => {
let n_details = [&orig.branch, &orig.tag, &orig.rev]
.iter()
.filter(|d| d.is_some())
.count();
if n_details > 1 {
bail!(
"dependency ({name_in_toml}) specification is ambiguous. \
Only one of `branch`, `tag` or `rev` is allowed.",
);
}
let reference = orig
.branch
.clone()
.map(GitReference::Branch)
.or_else(|| orig.tag.clone().map(GitReference::Tag))
.or_else(|| orig.rev.clone().map(GitReference::Rev))
.unwrap_or(GitReference::DefaultBranch);
let loc = git.into_url()?;
if let Some(fragment) = loc.fragment() {
let msg = format!(
"URL fragment `#{fragment}` in git URL is ignored for dependency ({name_in_toml}). \
If you were trying to specify a specific git revision, \
use `rev = \"{fragment}\"` in the dependency declaration.",
);
manifest_ctx.warnings.push(msg);
}
SourceId::for_git(&loc, reference)
}
(None, Some(path), _, _) => {
let path = path.resolve(manifest_ctx.gctx);
// If the source ID for the package we're parsing is a path
// source, then we normalize the path here to get rid of
// components like `..`.
//
// The purpose of this is to get a canonical ID for the package
// that we're depending on to ensure that builds of this package
// always end up hashing to the same value no matter where it's
// built from.
if manifest_ctx.source_id.is_path() {
let path = manifest_ctx.root.join(path);
let path = paths::normalize_path(&path);
SourceId::for_path(&path)
} else {
Ok(manifest_ctx.source_id)
}
}
(None, None, Some(registry), None) => SourceId::alt_registry(manifest_ctx.gctx, registry),
(None, None, None, Some(registry_index)) => {
let url = registry_index.into_url()?;
SourceId::for_registry(&url)
}
(None, None, None, None) => SourceId::crates_io(manifest_ctx.gctx),
}
}
pub trait ResolveToPath {
fn resolve(&self, gctx: &GlobalContext) -> PathBuf;
}
@ -2335,19 +2318,22 @@ fn deprecated_underscore<T>(
new_path: &str,
name: &str,
kind: &str,
edition: Edition,
warnings: &mut Vec<String>,
) {
if old.is_some() && new.is_some() {
let old_path = new_path.replace("-", "_");
) -> CargoResult<()> {
let old_path = new_path.replace("-", "_");
if old.is_some() && Edition::Edition2024 <= edition {
anyhow::bail!("`{old_path}` is unsupported as of the 2024 edition; instead use `{new_path}`\n(in the `{name}` {kind})");
} else if old.is_some() && new.is_some() {
warnings.push(format!(
"unused manifest key `{old_path}` in the `{name}` {kind}"
"`{old_path}` is redundant with `{new_path}`, preferring `{new_path}` in the `{name}` {kind}"
))
} else if old.is_some() {
let old_path = new_path.replace("-", "_");
warnings.push(format!(
"`{old_path}` is deprecated in favor of `{new_path}` and will not work in the 2024 edition\n(in the `{name}` {kind})"
))
}
Ok(())
}
fn warn_on_unused(unused: &BTreeSet<String>, warnings: &mut Vec<String>) {

View File

@ -97,12 +97,7 @@ pub(super) fn to_targets(
warnings,
errors,
)?;
targets.extend(to_example_targets(
&toml_examples,
package_root,
edition,
warnings,
)?);
targets.extend(to_example_targets(&toml_examples, package_root, edition)?);
let toml_tests = resolve_tests(
resolved_toml.test.as_ref(),
@ -183,6 +178,10 @@ fn resolve_lib(
// Check early to improve error messages
validate_lib_name(&lib, warnings)?;
// Checking the original lib
validate_proc_macro(&lib, "library", edition, warnings)?;
validate_crate_types(&lib, "library", edition, warnings)?;
if lib.path.is_none() {
if let Some(inferred) = inferred {
lib.path = Some(PathValue(inferred));
@ -218,8 +217,6 @@ fn to_lib_target(
let Some(lib) = resolved_lib else {
return Ok(None);
};
validate_proc_macro(lib, "library", warnings);
validate_crate_types(lib, "library", warnings);
let path = lib.path.as_ref().expect("previously resolved");
let path = package_root.join(&path.0);
@ -442,14 +439,12 @@ fn to_example_targets(
targets: &[TomlExampleTarget],
package_root: &Path,
edition: Edition,
warnings: &mut Vec<String>,
) -> CargoResult<Vec<Target>> {
validate_unique_names(&targets, "example")?;
let mut result = Vec::new();
for toml in targets {
let path = package_root.join(&toml.path.as_ref().expect("previously resolved").0);
validate_crate_types(&toml, "example", warnings);
let crate_types = match toml.crate_types() {
Some(kinds) => kinds.iter().map(|s| s.into()).collect(),
None => Vec::new(),
@ -637,6 +632,8 @@ fn resolve_targets_with_legacy_path(
for target in &toml_targets {
validate_target_name(target, target_kind_human, target_kind, warnings)?;
validate_proc_macro(target, target_kind_human, edition, warnings)?;
validate_crate_types(target, target_kind_human, edition, warnings)?;
}
let mut result = Vec::new();
@ -1101,24 +1098,36 @@ fn name_or_panic(target: &TomlTarget) -> &str {
.unwrap_or_else(|| panic!("target name is required"))
}
fn validate_proc_macro(target: &TomlTarget, kind: &str, warnings: &mut Vec<String>) {
fn validate_proc_macro(
target: &TomlTarget,
kind: &str,
edition: Edition,
warnings: &mut Vec<String>,
) -> CargoResult<()> {
deprecated_underscore(
&target.proc_macro2,
&target.proc_macro,
"proc-macro",
name_or_panic(target),
format!("{kind} target").as_str(),
edition,
warnings,
);
)
}
fn validate_crate_types(target: &TomlTarget, kind: &str, warnings: &mut Vec<String>) {
fn validate_crate_types(
target: &TomlTarget,
kind: &str,
edition: Edition,
warnings: &mut Vec<String>,
) -> CargoResult<()> {
deprecated_underscore(
&target.crate_type2,
&target.crate_type,
"crate-type",
name_or_panic(target),
format!("{kind} target").as_str(),
edition,
warnings,
);
)
}

View File

@ -339,6 +339,7 @@ This was stabilized in 1.79 in [#13608](https://github.com/rust-lang/cargo/pull/
`-Zmsrv-policy` allows access to an MSRV-aware resolver which can be enabled with:
- `resolver.something-like-precedence` config field
- `workspace.resolver = "3"` / `package.resolver = "3"`
- `package.edition = "2024"` (only in workspace root)
The resolver will prefer dependencies with a `package.rust-version` that is the same or older than your project's MSRV.
Your project's MSRV is determined by taking the lowest `package.rust-version` set among your workspace members.

View File

@ -80,10 +80,14 @@ edition = "2021" # the edition, will have no effect on a resolver used in th
authors = ["Alice <a@example.com>", "Bob <b@example.com>"]
```
Note that in a virtual manifest the [`resolver = "2"`](resolver.md#resolver-versions)
should be specified manually. It is usually deduced from the [`package.edition`][package-edition]
field which is absent in virtual manifests and the edition field of a member
won't affect the resolver used by the workspace.
By having a workspace without a root package,
- [`resolver`](resolver.md#resolver-versions) must be
set explicitly in virtual workspaces as they have no
[`package.edition`][package-edition] to infer it from
[resolver version](resolver.md#resolver-versions).
- Commands run in the workspace root will run against all workspace
members by default, see [`default-members`](#the-default-members-field).
## The `members` and `exclude` fields
@ -120,14 +124,12 @@ is not inside a subdirectory of the workspace root.
In a workspace, package-related Cargo commands like [`cargo build`] can use
the `-p` / `--package` or `--workspace` command-line flags to determine which
packages to operate on. If neither of those flags are specified, Cargo will
use the package in the current working directory. If the current directory is
a [virtual workspace](#virtual-workspace), it will apply to all members (as if
`--workspace` were specified on the command-line). See also
[`default-members`](#the-default-members-field).
use the package in the current working directory. However, if the current directory is
a workspace root, the [`default-members`](#the-default-members-field) will be used.
## The `default-members` field
The optional `default-members` key can be specified to set the members to
The `default-members` field specifies paths of [members](#the-members-and-exclude-fields) to
operate on when in the workspace root and the package selection flags are not
used:
@ -137,7 +139,12 @@ members = ["path/to/member1", "path/to/member2", "path/to/member3/*"]
default-members = ["path/to/member2", "path/to/member3/foo"]
```
When specified, `default-members` must expand to a subset of `members`.
> Note: when a [root package](#root-package) is present,
> you can only operate on it using `--package` and `--workspace` flags.
When unspecified, the [root package](#root-package) will be used.
In the case of a [virtual workspace](#virtual-workspace), all members will be used
(as if `--workspace` were specified on the command-line).
## The `package` table

View File

@ -1572,7 +1572,11 @@ or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN",
)
.run();
let crates_io = registry::RegistryBuilder::new()
.no_configure_token()
.build();
p.cargo("publish --registry crates-io")
.replace_crates_io(crates_io.index_url())
.with_status(101)
.with_stderr(
"\

View File

@ -841,6 +841,50 @@ fn dev_dependencies2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn dev_dependencies2_2024() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.1.0"
edition = "2024"
[dev_dependencies]
a = {path = "a"}
"#,
)
.file("src/lib.rs", "")
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.0.1"
edition = "2015"
"#,
)
.file("a/src/lib.rs", "")
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`dev_dependencies` is unsupported as of the 2024 edition; instead use `dev-dependencies`
(in the `foo` package)
",
)
.run();
}
#[cargo_test]
fn dev_dependencies2_conflict() {
let p = project()
@ -873,7 +917,7 @@ fn dev_dependencies2_conflict() {
p.cargo("check")
.with_stderr_contains(
"\
[WARNING] unused manifest key `dev_dependencies` in the `foo` package
[WARNING] `dev_dependencies` is redundant with `dev-dependencies`, preferring `dev-dependencies` in the `foo` package
",
)
.run();
@ -916,6 +960,50 @@ fn build_dependencies2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn build_dependencies2_2024() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.1.0"
edition = "2024"
[build_dependencies]
a = {path = "a"}
"#,
)
.file("src/lib.rs", "")
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.0.1"
edition = "2015"
"#,
)
.file("a/src/lib.rs", "")
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`build_dependencies` is unsupported as of the 2024 edition; instead use `build-dependencies`
(in the `foo` package)
",
)
.run();
}
#[cargo_test]
fn build_dependencies2_conflict() {
let p = project()
@ -948,7 +1036,7 @@ fn build_dependencies2_conflict() {
p.cargo("check")
.with_stderr_contains(
"\
[WARNING] unused manifest key `build_dependencies` in the `foo` package
[WARNING] `build_dependencies` is redundant with `build-dependencies`, preferring `build-dependencies` in the `foo` package
",
)
.run();
@ -983,6 +1071,42 @@ fn lib_crate_type2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn lib_crate_type2_2024() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.5.0"
edition = "2024"
authors = ["wycats@example.com"]
[lib]
name = "foo"
crate_type = ["staticlib", "dylib"]
"#,
)
.file("src/lib.rs", "pub fn foo() {}")
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`crate_type` is unsupported as of the 2024 edition; instead use `crate-type`
(in the `foo` library target)
",
)
.run();
}
#[cargo_test]
fn lib_crate_type2_conflict() {
let p = project()
@ -1006,7 +1130,7 @@ fn lib_crate_type2_conflict() {
p.cargo("check")
.with_stderr_contains(
"\
[WARNING] unused manifest key `crate_type` in the `foo` library target
[WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `foo` library target
",
)
.run();
@ -1060,6 +1184,59 @@ fn examples_crate_type2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn examples_crate_type2_2024() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.5.0"
edition = "2024"
authors = ["wycats@example.com"]
[[example]]
name = "ex"
path = "examples/ex.rs"
crate_type = ["proc_macro"]
[[example]]
name = "goodbye"
path = "examples/ex-goodbye.rs"
crate_type = ["rlib", "staticlib"]
"#,
)
.file("src/lib.rs", "")
.file(
"examples/ex.rs",
r#"
fn main() { println!("ex"); }
"#,
)
.file(
"examples/ex-goodbye.rs",
r#"
fn main() { println!("goodbye"); }
"#,
)
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`crate_type` is unsupported as of the 2024 edition; instead use `crate-type`
(in the `ex` example target)
",
)
.run();
}
#[cargo_test]
fn examples_crate_type2_conflict() {
let p = project()
@ -1101,8 +1278,8 @@ fn examples_crate_type2_conflict() {
p.cargo("check")
.with_stderr_contains(
"\
[WARNING] unused manifest key `crate_type` in the `ex` example target
[WARNING] unused manifest key `crate_type` in the `goodbye` example target
[WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `ex` example target
[WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `goodbye` example target
",
)
.run();
@ -1148,6 +1325,53 @@ fn cargo_platform_build_dependencies2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn cargo_platform_build_dependencies2_2024() {
let host = rustc_host();
let p = project()
.file(
"Cargo.toml",
&format!(
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.5.0"
edition = "2024"
authors = ["wycats@example.com"]
build = "build.rs"
[target.{host}.build_dependencies]
build = {{ path = "build" }}
"#,
host = host
),
)
.file("src/main.rs", "fn main() { }")
.file(
"build.rs",
"extern crate build; fn main() { build::build(); }",
)
.file("build/Cargo.toml", &basic_manifest("build", "0.5.0"))
.file("build/src/lib.rs", "pub fn build() {}")
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(format!(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`build_dependencies` is unsupported as of the 2024 edition; instead use `build-dependencies`
(in the `{host}` platform target)
"
))
.run();
}
#[cargo_test]
fn cargo_platform_build_dependencies2_conflict() {
let host = rustc_host();
@ -1183,7 +1407,7 @@ fn cargo_platform_build_dependencies2_conflict() {
p.cargo("check")
.with_stderr_contains(format!(
"\
[WARNING] unused manifest key `build_dependencies` in the `{host}` platform target
[WARNING] `build_dependencies` is redundant with `build-dependencies`, preferring `build-dependencies` in the `{host}` platform target
"
))
.run();
@ -1228,6 +1452,52 @@ fn cargo_platform_dev_dependencies2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn cargo_platform_dev_dependencies2_2024() {
let host = rustc_host();
let p = project()
.file(
"Cargo.toml",
&format!(
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.5.0"
edition = "2024"
authors = ["wycats@example.com"]
[target.{host}.dev_dependencies]
dev = {{ path = "dev" }}
"#,
host = host
),
)
.file("src/main.rs", "fn main() { }")
.file(
"tests/foo.rs",
"extern crate dev; #[test] fn foo() { dev::dev() }",
)
.file("dev/Cargo.toml", &basic_manifest("dev", "0.5.0"))
.file("dev/src/lib.rs", "pub fn dev() {}")
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(format!(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`dev_dependencies` is unsupported as of the 2024 edition; instead use `dev-dependencies`
(in the `{host}` platform target)
"
))
.run();
}
#[cargo_test]
fn cargo_platform_dev_dependencies2_conflict() {
let host = rustc_host();
@ -1262,7 +1532,7 @@ fn cargo_platform_dev_dependencies2_conflict() {
p.cargo("check")
.with_stderr_contains(format!(
"\
[WARNING] unused manifest key `dev_dependencies` in the `{host}` platform target
[WARNING] `dev_dependencies` is redundant with `dev-dependencies`, preferring `dev-dependencies` in the `{host}` platform target
"
))
.run();
@ -1312,6 +1582,57 @@ fn default_features2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn default_features2_2024() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.1.0"
edition = "2024"
authors = []
[dependencies]
a = { path = "a", features = ["f1"], default_features = false }
"#,
)
.file("src/lib.rs", "")
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.1.0"
edition = "2015"
authors = []
[features]
default = ["f1"]
f1 = []
"#,
)
.file("a/src/lib.rs", "")
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`default_features` is unsupported as of the 2024 edition; instead use `default-features`
(in the `a` dependency)
",
)
.run();
}
#[cargo_test]
fn default_features2_conflict() {
let p = project()
@ -1349,7 +1670,182 @@ fn default_features2_conflict() {
p.cargo("check")
.with_stderr_contains(
"\
[WARNING] unused manifest key `default_features` in the `a` dependency
[WARNING] `default_features` is redundant with `default-features`, preferring `default-features` in the `a` dependency
",
)
.run();
}
#[cargo_test]
fn workspace_default_features2() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["workspace_only", "dep_workspace_only", "package_only", "dep_package_only"]
[workspace.dependencies]
dep_workspace_only = { path = "dep_workspace_only", default_features = true }
dep_package_only = { path = "dep_package_only" }
"#,
)
.file(
"workspace_only/Cargo.toml",
r#"
[package]
name = "workspace_only"
version = "0.1.0"
edition = "2015"
authors = []
[dependencies]
dep_workspace_only.workspace = true
"#,
)
.file("workspace_only/src/lib.rs", "")
.file(
"dep_workspace_only/Cargo.toml",
r#"
[package]
name = "dep_workspace_only"
version = "0.1.0"
edition = "2015"
authors = []
"#,
)
.file("dep_workspace_only/src/lib.rs", "")
.file(
"package_only/Cargo.toml",
r#"
[package]
name = "package_only"
version = "0.1.0"
edition = "2015"
authors = []
[dependencies]
dep_package_only = { workspace = true, default_features = true }
"#,
)
.file("package_only/src/lib.rs", "")
.file(
"dep_package_only/Cargo.toml",
r#"
[package]
name = "dep_package_only"
version = "0.1.0"
edition = "2015"
authors = []
"#,
)
.file("dep_package_only/src/lib.rs", "")
.build();
p.cargo("check")
.with_stderr_unordered(
"\
warning: [CWD]/workspace_only/Cargo.toml: `default_features` is deprecated in favor of `default-features` and will not work in the 2024 edition
(in the `dep_workspace_only` dependency)
Locking 4 packages to latest compatible versions
Checking dep_package_only v0.1.0 ([CWD]/dep_package_only)
Checking dep_workspace_only v0.1.0 ([CWD]/dep_workspace_only)
Checking package_only v0.1.0 ([CWD]/package_only)
Checking workspace_only v0.1.0 ([CWD]/workspace_only)
Finished `dev` profile [unoptimized + debuginfo] target(s) in [..]s
"
)
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn workspace_default_features2_2024() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["workspace_only", "dep_workspace_only", "package_only", "dep_package_only"]
[workspace.dependencies]
dep_workspace_only = { path = "dep_workspace_only", default_features = true }
dep_package_only = { path = "dep_package_only" }
"#,
)
.file(
"workspace_only/Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "workspace_only"
version = "0.1.0"
edition = "2024"
authors = []
[dependencies]
dep_workspace_only.workspace = true
"#,
)
.file("workspace_only/src/lib.rs", "")
.file(
"dep_workspace_only/Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "dep_workspace_only"
version = "0.1.0"
edition = "2024"
authors = []
"#,
)
.file("dep_workspace_only/src/lib.rs", "")
.file(
"package_only/Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "package_only"
version = "0.1.0"
edition = "2024"
authors = []
[dependencies]
dep_package_only = { workspace = true, default_features = true }
"#,
)
.file("package_only/src/lib.rs", "")
.file(
"dep_package_only/Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "dep_package_only"
version = "0.1.0"
edition = "2024"
authors = []
"#,
)
.file("dep_package_only/src/lib.rs", "")
.build();
p.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(
"\
[ERROR] failed to load manifest for workspace member `[CWD]/workspace_only`
referenced by workspace at `[CWD]/Cargo.toml`
Caused by:
failed to parse manifest at `[CWD]/workspace_only/Cargo.toml`
Caused by:
`default_features` is unsupported as of the 2024 edition; instead use `default-features`
(in the `dep_workspace_only` dependency)
",
)
.run();
@ -1382,6 +1878,40 @@ fn proc_macro2() {
.run();
}
#[cargo_test(nightly, reason = "edition2024 is not stable")]
fn proc_macro2_2024() {
let foo = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.1.0"
edition = "2024"
[lib]
proc_macro = true
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
`proc_macro` is unsupported as of the 2024 edition; instead use `proc-macro`
(in the `foo` library target)
",
)
.run();
}
#[cargo_test]
fn proc_macro2_conflict() {
let foo = project()
@ -1403,7 +1933,7 @@ fn proc_macro2_conflict() {
foo.cargo("check")
.with_stderr_contains(
"\
[WARNING] unused manifest key `proc_macro` in the `foo` library target
[WARNING] `proc_macro` is redundant with `proc-macro`, preferring `proc-macro` in the `foo` library target
",
)
.run();

View File

@ -5502,6 +5502,39 @@ for more information about build script outputs.
.run();
}
#[cargo_test]
fn test_new_syntax_with_compatible_partial_msrv() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
edition = "2015"
build = "build.rs"
rust-version = "1.77"
"#,
)
.file("src/lib.rs", "")
.file(
"build.rs",
r#"
fn main() {
println!("cargo::metadata=foo=bar");
}
"#,
)
.build();
p.cargo("check")
.with_stderr_contains(
"\
[COMPILING] foo [..]
",
)
.run();
}
#[cargo_test]
fn test_old_syntax_with_old_msrv() {
let p = project()

View File

@ -184,12 +184,29 @@ fn symlink_file(target: &Path, link: &Path) -> io::Result<()> {
os::windows::fs::symlink_file(target, link)
}
fn symlink_config_to_config_toml() {
fn make_config_symlink_to_config_toml_absolute() {
let toml_path = paths::root().join(".cargo/config.toml");
let symlink_path = paths::root().join(".cargo/config");
t!(symlink_file(&toml_path, &symlink_path));
}
fn make_config_symlink_to_config_toml_relative() {
let symlink_path = paths::root().join(".cargo/config");
t!(symlink_file(Path::new("config.toml"), &symlink_path));
}
fn rename_config_toml_to_config_replacing_with_symlink() {
let root = paths::root();
t!(fs::rename(
root.join(".cargo/config.toml"),
root.join(".cargo/config")
));
t!(symlink_file(
Path::new("config"),
&root.join(".cargo/config.toml")
));
}
#[track_caller]
pub fn assert_error<E: Borrow<anyhow::Error>>(error: E, msgs: &str) {
let causes = error
@ -298,7 +315,7 @@ f1 = 1
",
);
symlink_config_to_config_toml();
make_config_symlink_to_config_toml_absolute();
let gctx = new_gctx();
@ -309,6 +326,58 @@ f1 = 1
assert_match("", &output);
}
#[cargo_test]
fn config_ambiguous_filename_symlink_doesnt_warn_relative() {
// Windows requires special permissions to create symlinks.
// If we don't have permission, just skip this test.
if !symlink_supported() {
return;
};
write_config_toml(
"\
[foo]
f1 = 1
",
);
make_config_symlink_to_config_toml_relative();
let gctx = new_gctx();
assert_eq!(gctx.get::<Option<i32>>("foo.f1").unwrap(), Some(1));
// It should NOT have warned for the symlink.
let output = read_output(gctx);
assert_match("", &output);
}
#[cargo_test]
fn config_ambiguous_filename_symlink_doesnt_warn_backward() {
// Windows requires special permissions to create symlinks.
// If we don't have permission, just skip this test.
if !symlink_supported() {
return;
};
write_config_toml(
"\
[foo]
f1 = 1
",
);
rename_config_toml_to_config_replacing_with_symlink();
let gctx = new_gctx();
assert_eq!(gctx.get::<Option<i32>>("foo.f1").unwrap(), Some(1));
// It should NOT have warned for this situation.
let output = read_output(gctx);
assert_match("", &output);
}
#[cargo_test]
fn config_ambiguous_filename() {
write_config_extless(

View File

@ -2050,6 +2050,149 @@ edition = "2021"
);
}
#[cargo_test]
fn migrate_rename_underscore_fields() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[workspace.dependencies]
# Before default_features
a = {path = "a", default_features = false} # After default_features value
# After default_features line
[package]
name = "foo"
edition = "2021"
[lib]
name = "foo"
# Before crate_type
crate_type = ["staticlib", "dylib"] # After crate_type value
# After crate_type line
[[example]]
name = "ex"
path = "examples/ex.rs"
# Before crate_type
crate_type = ["proc-macro"] # After crate_type value
# After crate_type line
# Before dev_dependencies
[ dev_dependencies ] # After dev_dependencies header
# After dev_dependencies line
a = {path = "a", default_features = false}
# After dev_dependencies table
# Before build_dependencies
[ build_dependencies ] # After build_dependencies header
# After build_dependencies line
a = {path = "a", default_features = false}
# After build_dependencies table
# Before dev_dependencies
[ target.'cfg(any())'.dev_dependencies ] # After dev_dependencies header
# After dev_dependencies line
a = {path = "a", default_features = false}
# After dev_dependencies table
# Before build_dependencies
[ target.'cfg(any())'.build_dependencies ] # After build_dependencies header
# After build_dependencies line
a = {path = "a", default_features = false}
# After build_dependencies table
"#,
)
.file("src/lib.rs", "")
.file(
"examples/ex.rs",
r#"
fn main() { println!("ex"); }
"#,
)
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.0.1"
edition = "2015"
"#,
)
.file("a/src/lib.rs", "")
.build();
p.cargo("fix --edition --allow-no-vcs")
.masquerade_as_nightly_cargo(&["edition2024"])
.with_stderr(
"\
[MIGRATING] Cargo.toml from 2021 edition to 2024
[FIXED] Cargo.toml (11 fixes)
Locking 2 packages to latest compatible versions
Checking a v0.0.1 ([CWD]/a)
[CHECKING] foo v0.0.0 ([CWD])
[MIGRATING] src/lib.rs from 2021 edition to 2024
[MIGRATING] examples/ex.rs from 2021 edition to 2024
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s
",
)
.run();
assert_eq!(
p.read_file("Cargo.toml"),
r#"
cargo-features = ["edition2024"]
[workspace.dependencies]
# Before default_features
a = {path = "a", default-features = false} # After default_features value
# After default_features line
[package]
name = "foo"
edition = "2021"
[lib]
name = "foo"
# Before crate_type
crate-type = ["staticlib", "dylib"] # After crate_type value
# After crate_type line
[[example]]
name = "ex"
path = "examples/ex.rs"
# Before crate_type
crate-type = ["proc-macro"] # After crate_type value
# After crate_type line
# Before dev_dependencies
[ dev-dependencies ] # After dev_dependencies header
# After dev_dependencies line
a = {path = "a", default-features = false}
# After dev_dependencies table
# Before build_dependencies
[ build-dependencies ] # After build_dependencies header
# After build_dependencies line
a = {path = "a", default-features = false}
# After build_dependencies table
# Before dev_dependencies
[ target.'cfg(any())'.dev-dependencies ] # After dev_dependencies header
# After dev_dependencies line
a = {path = "a", default-features = false}
# After dev_dependencies table
# Before build_dependencies
[ target.'cfg(any())'.build-dependencies ] # After build_dependencies header
# After build_dependencies line
a = {path = "a", default-features = false}
# After build_dependencies table
"#,
);
}
#[cargo_test]
fn add_feature_for_unused_dep() {
Package::new("bar", "0.1.0").publish();

View File

@ -30,9 +30,6 @@ fn permit_additional_workspace_fields() {
exclude = ["foo.txt"]
include = ["bar.txt", "**/*.rs", "Cargo.toml", "LICENSE", "README.md"]
[workspace.package.badges]
gitlab = { repository = "https://gitlab.com/rust-lang/rust", branch = "master" }
[workspace.dependencies]
dep = "0.1"
"#,
@ -117,8 +114,6 @@ fn inherit_own_workspace_fields() {
.file(
"Cargo.toml",
r#"
badges.workspace = true
[package]
name = "foo"
version.workspace = true
@ -153,8 +148,6 @@ fn inherit_own_workspace_fields() {
rust-version = "1.60"
exclude = ["foo.txt"]
include = ["bar.txt", "**/*.rs", "Cargo.toml"]
[workspace.package.badges]
gitlab = { repository = "https://gitlab.com/rust-lang/rust", branch = "master" }
"#,
)
.file("src/main.rs", "fn main() {}")
@ -186,9 +179,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly.
r#"
{
"authors": ["Rustaceans"],
"badges": {
"gitlab": { "branch": "master", "repository": "https://gitlab.com/rust-lang/rust" }
},
"badges": {},
"categories": ["development-tools"],
"deps": [],
"description": "This is a crate",
@ -240,10 +231,6 @@ keywords = ["cli"]
categories = ["development-tools"]
license = "MIT"
repository = "https://github.com/example/example"
[badges.gitlab]
branch = "master"
repository = "https://gitlab.com/rust-lang/rust"
"#,
cargo::core::manifest::MANIFEST_PREAMBLE
),
@ -665,15 +652,12 @@ fn inherit_workspace_fields() {
rust-version = "1.60"
exclude = ["foo.txt"]
include = ["bar.txt", "**/*.rs", "Cargo.toml", "LICENSE", "README.md"]
[workspace.package.badges]
gitlab = { repository = "https://gitlab.com/rust-lang/rust", branch = "master" }
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"bar/Cargo.toml",
r#"
badges.workspace = true
[package]
name = "bar"
workspace = ".."
@ -731,9 +715,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly.
r#"
{
"authors": ["Rustaceans"],
"badges": {
"gitlab": { "branch": "master", "repository": "https://gitlab.com/rust-lang/rust" }
},
"badges": {},
"categories": ["development-tools"],
"deps": [],
"description": "This is a crate",
@ -791,10 +773,6 @@ categories = ["development-tools"]
license = "MIT"
license-file = "LICENSE"
repository = "https://github.com/example/example"
[badges.gitlab]
branch = "master"
repository = "https://gitlab.com/rust-lang/rust"
"#,
cargo::core::manifest::MANIFEST_PREAMBLE
),
@ -1715,8 +1693,6 @@ fn warn_inherit_unused_manifest_key_package() {
.file(
"Cargo.toml",
r#"
badges = { workspace = true, xyz = "abc"}
[workspace]
members = []
[workspace.package]
@ -1734,8 +1710,6 @@ fn warn_inherit_unused_manifest_key_package() {
rust-version = "1.60"
exclude = ["foo.txt"]
include = ["bar.txt", "**/*.rs", "Cargo.toml"]
[workspace.package.badges]
gitlab = { repository = "https://gitlab.com/rust-lang/rust", branch = "master" }
[package]
name = "bar"

View File

@ -1981,7 +1981,7 @@ fn install_ignores_unstable_table_in_local_cargo_config() {
fn install_global_cargo_config() {
pkg("bar", "0.0.1");
let config = cargo_home().join("config");
let config = cargo_home().join("config.toml");
let mut toml = fs::read_to_string(&config).unwrap_or_default();
toml.push_str(
@ -1994,6 +1994,7 @@ fn install_global_cargo_config() {
cargo_process("install bar")
.with_status(101)
.with_stderr_contains("[INSTALLING] bar v0.0.1")
.with_stderr_contains("[..]--target nonexistent[..]")
.run();
}

View File

@ -33,7 +33,7 @@
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-green bold">note</tspan><tspan>: `cargo::implicit_features` is set to `warn`</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-green bold">note</tspan><tspan>: `cargo::implicit_features` is set to `warn` in `[lints]`</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan class="fg-yellow bold">warning</tspan><tspan>: </tspan><tspan class="bold">implicit features for optional dependencies is deprecated and will be unavailable in the 2024 edition</tspan>
</tspan>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -20,7 +20,7 @@
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Locking</tspan><tspan> 2 packages to latest compatible versions</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Locking</tspan><tspan> 2 packages to latest Rust [..] compatible versions</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan class="fg-green bold"> Checking</tspan><tspan> foo v0.1.0 ([ROOT]/foo)</tspan>
</tspan>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -33,9 +33,10 @@ target-dep = { version = "0.1.0", optional = true }
.build();
snapbox::cmd::Command::cargo_ui()
.masquerade_as_nightly_cargo(&["edition2024"])
.masquerade_as_nightly_cargo(&["cargo-lints", "edition2024"])
.current_dir(p.root())
.arg("check")
.arg("-Zcargo-lints")
.assert()
.success()
.stdout_matches(str![""])

View File

@ -34,7 +34,7 @@
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-green bold">note</tspan><tspan>: `cargo::unused_optional_dependency` is set to `warn`</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-green bold">note</tspan><tspan>: `cargo::unused_optional_dependency` is set to `warn` by default</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-cyan bold">help</tspan><tspan>: remove the dependency or activate it in a feature with `dep:bar`</tspan>
</tspan>

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -32,9 +32,10 @@ target-dep = { version = "0.1.0", optional = true }
.build();
snapbox::cmd::Command::cargo_ui()
.masquerade_as_nightly_cargo(&["edition2024"])
.masquerade_as_nightly_cargo(&["cargo-lints", "edition2024"])
.current_dir(p.root())
.arg("check")
.arg("-Zcargo-lints")
.assert()
.success()
.stdout_matches(str![""])

View File

@ -34,7 +34,7 @@
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-green bold">note</tspan><tspan>: `cargo::unused_optional_dependency` is set to `warn`</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-green bold">note</tspan><tspan>: `cargo::unused_optional_dependency` is set to `warn` by default</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">=</tspan><tspan> </tspan><tspan class="fg-bright-cyan bold">help</tspan><tspan>: remove the dependency or activate it in a feature with `dep:bar`</tspan>
</tspan>

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -756,14 +756,14 @@ fn cargo_lints_nightly_required() {
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
[lints.cargo]
"unused-features" = "deny"
[lints.cargo]
im-a-teapot = "warn"
"#,
)
.file("src/lib.rs", "")
@ -790,21 +790,24 @@ fn cargo_lints_no_z_flag() {
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
cargo-features = ["test-dummy-unstable"]
[lints.cargo]
"unused-features" = "deny"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
[lints.cargo]
im-a-teapot = "warn"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check")
.masquerade_as_nightly_cargo(&["-Zcargo-lints"])
.masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"])
.with_stderr(
"\
[WARNING] unused manifest key `lints.cargo` (may be supported in a future version)
@ -819,27 +822,37 @@ consider passing `-Zcargo-lints` to enable this feature.
#[cargo_test]
fn cargo_lints_success() {
let foo = project()
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
cargo-features = ["test-dummy-unstable"]
[lints.cargo]
"unused-features" = "deny"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
[lints.cargo]
im-a-teapot = "warn"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["-Zcargo-lints"])
p.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"])
.with_stderr(
"\
warning: `im_a_teapot` is specified
--> Cargo.toml:9:1
|
9 | im-a-teapot = true
| ------------------
|
= note: `cargo::im_a_teapot` is set to `warn` in `[lints]`
[CHECKING] foo v0.0.1 ([CWD])
[FINISHED] [..]
",
@ -849,43 +862,163 @@ fn cargo_lints_success() {
#[cargo_test]
fn cargo_lints_underscore_supported() {
Package::new("bar", "0.1.0").publish();
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2021"
authors = []
cargo-features = ["test-dummy-unstable"]
[lints.cargo]
"implicit_features" = "warn"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
[dependencies]
bar = { version = "0.1.0", optional = true }
[lints.cargo]
im_a_teapot = "warn"
"#,
)
.file("src/lib.rs", "")
.build();
foo.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["-Zcargo-lints"])
.masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"])
.with_stderr(
"\
warning: implicit features for optional dependencies is deprecated and will be unavailable in the 2024 edition
--> Cargo.toml:12:17
|
12 | bar = { version = \"0.1.0\", optional = true }
| ---
|
= note: `cargo::implicit_features` is set to `warn`
[UPDATING] `dummy-registry` index
[LOCKING] [..]
warning: `im_a_teapot` is specified
--> Cargo.toml:9:1
|
9 | im-a-teapot = true
| ------------------
|
= note: `cargo::im_a_teapot` is set to `warn` in `[lints]`
[CHECKING] foo v0.0.1 ([CWD])
[FINISHED] [..]
",
)
.run();
}
#[cargo_test]
fn forbid_not_overridden() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["test-dummy-unstable"]
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
[lints.cargo]
im-a-teapot = { level = "warn", priority = 10 }
test-dummy-unstable = { level = "forbid", priority = -1 }
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"])
.with_status(101)
.with_stderr(
"\
error: `im_a_teapot` is specified
--> Cargo.toml:9:1
|
9 | im-a-teapot = true
| ^^^^^^^^^^^^^^^^^^
|
= note: `cargo::im_a_teapot` is set to `forbid` in `[lints]`
",
)
.run();
}
#[cargo_test]
fn workspace_cargo_lints() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["test-dummy-unstable"]
[workspace.lints.cargo]
im-a-teapot = { level = "warn", priority = 10 }
test-dummy-unstable = { level = "forbid", priority = -1 }
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
[lints]
workspace = true
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"])
.with_status(101)
.with_stderr(
"\
error: `im_a_teapot` is specified
--> Cargo.toml:13:1
|
13 | im-a-teapot = true
| ^^^^^^^^^^^^^^^^^^
|
= note: `cargo::im_a_teapot` is set to `forbid` in `[workspace.lints]`
",
)
.run();
}
#[cargo_test]
fn dont_always_inherit_workspace_lints() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["foo"]
[workspace.lints.cargo]
im-a-teapot = "warn"
"#,
)
.file(
"foo/Cargo.toml",
r#"
cargo-features = ["test-dummy-unstable"]
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
"#,
)
.file("foo/src/lib.rs", "")
.build();
p.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["cargo-lints"])
.with_stderr(
"\
[CHECKING] foo v0.0.1 ([CWD]/foo)
[FINISHED] [..]
",
)
.run();
}

View File

@ -613,6 +613,117 @@ foo v0.0.1 ([CWD])
.run();
}
#[cargo_test(nightly, reason = "edition2024 in rustc is unstable")]
fn resolve_edition2024() {
Package::new("only-newer", "1.6.0")
.rust_version("1.65.0")
.file("src/lib.rs", "fn other_stuff() {}")
.publish();
Package::new("newer-and-older", "1.5.0")
.rust_version("1.55.0")
.file("src/lib.rs", "fn other_stuff() {}")
.publish();
Package::new("newer-and-older", "1.6.0")
.rust_version("1.65.0")
.file("src/lib.rs", "fn other_stuff() {}")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["edition2024"]
[package]
name = "foo"
version = "0.0.1"
edition = "2024"
authors = []
rust-version = "1.60.0"
[dependencies]
only-newer = "1.0.0"
newer-and-older = "1.0.0"
"#,
)
.file("src/main.rs", "fn main(){}")
.build();
// Edition2024 should resolve for MSRV
p.cargo("generate-lockfile")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stderr(
"\
[UPDATING] `dummy-registry` index
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
",
)
.run();
p.cargo("tree")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stdout(
"\
foo v0.0.1 ([CWD])
newer-and-older v1.5.0
only-newer v1.6.0
",
)
.run();
// `--ignore-rust-version` has precedence over Edition2024
p.cargo("generate-lockfile --ignore-rust-version")
.with_stderr(
"\
[UPDATING] `dummy-registry` index
[LOCKING] 3 packages to latest compatible versions
",
)
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["msrv-policy"])
.run();
p.cargo("tree")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stdout(
"\
foo v0.0.1 ([CWD])
newer-and-older v1.6.0
only-newer v1.6.0
",
)
.run();
// config has precedence over Edition2024
p.cargo("generate-lockfile")
.env(
"CARGO_RESOLVER_SOMETHING_LIKE_PRECEDENCE",
"something-like-maximum",
)
.with_stderr(
"\
[UPDATING] `dummy-registry` index
[LOCKING] 3 packages to latest compatible versions
",
)
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["msrv-policy"])
.run();
p.cargo("tree")
.arg("-Zmsrv-policy")
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
.with_stdout(
"\
foo v0.0.1 ([CWD])
newer-and-older v1.6.0
only-newer v1.6.0
",
)
.run();
}
#[cargo_test(nightly, reason = "edition2024 in rustc is unstable")]
fn resolve_v3() {
Package::new("only-newer", "1.6.0")
@ -1035,11 +1146,10 @@ fn cargo_install_ignores_msrv_config() {
[DOWNLOADING] crates ...
[DOWNLOADED] foo v0.0.1 (registry [..])
[INSTALLING] foo v0.0.1
[LOCKING] 2 packages to latest Rust 1.60 compatible versions
[ADDING] dep v1.0.0 (latest: v1.1.0)
[LOCKING] 2 packages to latest compatible versions
[DOWNLOADING] crates ...
[DOWNLOADED] dep v1.0.0 (registry [..])
[COMPILING] dep v1.0.0
[DOWNLOADED] dep v1.1.0 (registry [..])
[COMPILING] dep v1.1.0
[COMPILING] foo v0.0.1
[FINISHED] `release` profile [optimized] target(s) in [..]
[INSTALLING] [CWD]/home/.cargo/bin/foo[EXE]