Repository: rust-lang/cargo (rust)

Issue:
re-vendored suggestion is incorrect with sparse crates.io
### Problem

The error message for a resolver activation error includes this comment when used with crates.io:

```
perhaps a crate was updated and forgotten to be re-vendored?
```

This is not correct. This message should only be displayed when vendoring is enabled. Cargo is getting confused somehow, thinking index.crates.io is a replaced source. This message should only be displayed when vendoring is actually enabled.


### Steps

Try to build with:

```toml
[dependencies]
regex = "99"
```

displays:

```
    Updating crates.io index
error: failed to select a version for the requirement `regex = "^99"`
candidate versions found which didn't match: 1.10.0, 1.9.6, 1.9.5, ...
location searched: crates.io index
required by package `foo v0.1.0 (/Users/eric/Temp/foo)`
perhaps a crate was updated and forgotten to be re-vendored?
```


### Possible Solution(s)

The error message is generated [here](https://github.com/rust-lang/cargo/blob/e4fe8f04e76dd6172dce67a840bfc6a1ebacd76a/src/cargo/core/resolver/errors.rs#L297-L299).

I'm uncertain at this moment why the source seems to be replaced. I vaguely recall having cargo treat index.crates.io as equivalent for the git index, but I forget how that all works.

### Notes

_No response_

### Version

```text
cargo 1.75.0-nightly (794d0a825 2023-10-03)
release: 1.75.0-nightly
commit-hash: 794d0a82547f3081044c0aca7b6083733ce51344
commit-date: 2023-10-03
host: aarch64-apple-darwin
libgit2: 1.7.1 (sys:0.18.1 vendored)
libcurl: 8.1.2 (sys:0.4.66+curl-8.3.0 system ssl:(SecureTransport) LibreSSL/3.3.6)
ssl: OpenSSL 1.1.1u  30 May 2023
os: Mac OS 14.0.0 [64-bit]
```


Pull request:
Silence the warning about forgetting the vendoring
<!-- homu-ignore:start -->
<!--
Thanks for submitting a pull request 🎉! Here are some tips for you:

* If this is your first contribution, read "Cargo Contribution Guide" first:
  https://doc.crates.io/contrib/
* Run `cargo fmt --all` to format your code changes.
* Small commits and pull requests are always preferable and easy to review.
* If your idea is large and needs feedback from the community, read how:
  https://doc.crates.io/contrib/process/#working-on-large-features
* Cargo takes care of compatibility. Read our design principles:
  https://doc.crates.io/contrib/design.html
* When changing help text of cargo commands, follow the steps to generate docs:
  https://github.com/rust-lang/cargo/tree/master/src/doc#building-the-man-pages
* If your PR is not finished, set it as "draft" PR or add "WIP" in its title.
* It's ok to use the CI resources to test your PR, but please don't abuse them.

### What does this PR try to resolve?

Explain the motivation behind this change.
A clear overview along with an in-depth explanation are helpful.

You can use `Fixes #<issue number>` to associate this PR to an existing issue.

### How should we test and review this PR?

Demonstrate how you test this change and guide reviewers through your PR.
With a smooth review process, a pull request usually gets reviewed quicker.

If you don't know how to write and run your tests, please read the guide:
https://doc.crates.io/contrib/tests

### Additional information

Other information you want to mention in this PR, such as prior arts,
future extensions, an unresolved problem, or a TODO list.
-->
When sparse crates.io is used, dependencies from crates.io always come from `ReplacedSource`s, as the non-sparse crates.io gets replaced by the sparse one. As far as diagnostics go, this case shouldn't "count" as a replaced source.

I had trouble adding a test for this change, because the test harness replaces everything with a dummy registry.

Fixes #12802 
<!-- homu-ignore:end -->


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5920bac27..a94f71f62 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,9 +48,8 @@
   This behavior has been considered a bug from the beginning.
   [#13775](https://github.com/rust-lang/cargo/pull/13775)
 - ❗️ Replace dashes with underscores also if `lib.name` is inferred from `package.name`.
-  This change aligns to the documented behavior. One caveat is that JSON messages
-  emitted by Cargo, like via `cargo metadata` or `--message-format=json`,
-  will start reporting underscore lib names.
+  This change aligns to the documented behavior. One caveat is that
+  `cargo metadata` starts reporting underscore lib names.
   [#12783](https://github.com/rust-lang/cargo/pull/12783)
 - Switch to `gitoxide` for listing files. This improves the performance of
   build script and `cargo doc` for computing cache freshness,
@@ -63,14 +62,14 @@
   [#13632](https://github.com/rust-lang/cargo/pull/13632)
 - Warn on unused `workspace.dependencies` keys on virtual workspaces.
   [#13664](https://github.com/rust-lang/cargo/pull/13664)
-- Emit 1.77 build script syntax error only when msrv is incompatible.
-  [#13808](https://github.com/rust-lang/cargo/pull/13808)
 - cargo-init: don't assign `target.name` in Cargo.toml if the value can be inferred.
   [#13606](https://github.com/rust-lang/cargo/pull/13606)
 - cargo-package: normalize paths in `Cargo.toml`, including replacing `\` with `/`.
   [#13729](https://github.com/rust-lang/cargo/pull/13729)
 - cargo-test: recategorize cargo test's `--doc` flag under “Target Selection”.
   [#13756](https://github.com/rust-lang/cargo/pull/13756)
+- Emit 1.77 build script syntax error only when msrv is incompatible.
+  [#13808](https://github.com/rust-lang/cargo/pull/13808)
 
 ### Fixed
 
@@ -81,6 +80,16 @@
   [#13618](https://github.com/rust-lang/cargo/pull/13618)
 - Don't crash on Cargo.toml parse errors that point to multi-byte character
   [#13780](https://github.com/rust-lang/cargo/pull/13780)
+- cargo-add: Maintain sorting of dependency features.
+  [#13682](https://github.com/rust-lang/cargo/pull/13682)
+- cargo-add: Preserve comments when updating simple deps
+  [#13655](https://github.com/rust-lang/cargo/pull/13655)
+- cargo-fix: dont apply same suggestion twice.
+  [#13728](https://github.com/rust-lang/cargo/pull/13728)
+- cargo-package: error when the package specified via `--package` cannot be found
+  [#13735](https://github.com/rust-lang/cargo/pull/13735)
+- credential-provider: trim newlines in tokens from stdin.
+  [#13770](https://github.com/rust-lang/cargo/pull/13770)
 - Don't emit deprecation warning if one of `.cargo/{config,config.toml}` is
   a symlink to the other.
   [#13793](https://github.com/rust-lang/cargo/pull/13793)
@@ -92,16 +101,6 @@
   [#13560](https://github.com/rust-lang/cargo/pull/13560)
 - Fix doc collision for lib/bin with a dash in the inferred name.
   [#13640](https://github.com/rust-lang/cargo/pull/13640)
-- cargo-add: Maintain sorting of dependency features.
-  [#13682](https://github.com/rust-lang/cargo/pull/13682)
-- cargo-add: Preserve comments when updating simple deps
-  [#13655](https://github.com/rust-lang/cargo/pull/13655)
-- cargo-fix: dont apply same suggestion twice.
-  [#13728](https://github.com/rust-lang/cargo/pull/13728)
-- cargo-package: error when the package specified via `--package` cannot be found
-  [#13735](https://github.com/rust-lang/cargo/pull/13735)
-- credential-provider: trim newlines in tokens from stdin.
-  [#13770](https://github.com/rust-lang/cargo/pull/13770)
 
 ### Nightly only
 
diff --git a/src/cargo/sources/replaced.rs b/src/cargo/sources/replaced.rs
index 72b255963..c64257908 100644
--- a/src/cargo/sources/replaced.rs
+++ b/src/cargo/sources/replaced.rs
@@ -152,7 +152,7 @@ impl<'gctx> Source for ReplacedSource<'gctx> {
     }
 
     fn is_replaced(&self) -> bool {
-        true
+        !self.is_builtin_replacement()
     }
 
     fn add_to_yanked_whitelist(&mut self, pkgs: &[PackageId]) {
diff --git a/src/cargo/sources/source.rs b/src/cargo/sources/source.rs
index b3dec06b4..14d3e0ac9 100644
--- a/src/cargo/sources/source.rs
+++ b/src/cargo/sources/source.rs
@@ -146,6 +146,8 @@ pub trait Source {
     fn describe(&self) -> String;
 
     /// Returns whether a source is being replaced by another here.
+    ///
+    /// Builtin replacement of `crates.io` doesn't count as replacement here.
     fn is_replaced(&self) -> bool {
         false
     }
diff --git a/src/doc/src/reference/build-scripts.md b/src/doc/src/reference/build-scripts.md
index a540de7a3..1f1fd0041 100644
--- a/src/doc/src/reference/build-scripts.md
+++ b/src/doc/src/reference/build-scripts.md
@@ -292,32 +292,6 @@ if foo_bar_condition {
 }
 ```
 
-##### Example of local-only `build.rs`/build script
-
-Build scripts can impose costs on downstream users, and crate authors who wish to avoid
-this can use "local-only" build scripts, which are active locally but not packaged in the
-distributed package. Completly removing the cost from downstream users. 
-
-The way to achieved this, is by excluding the `build.rs` in the `Cargo.toml` with the
-`exclude` key:
-
-```diff
-  [package]
-  name = "foo"
-  version = "0.1.0"
-+ exclude = ["build.rs"]
-```
-
-*`build.rs`:*
-```rust
-fn main() {
-    // Warning: build.rs is not published to crates.io.
-
-    println!("cargo::rerun-if-changed=build.rs");
-    println!("cargo::rustc-check-cfg=cfg(foo)");
-}
-```
-
 For a more complete example see in the [build script examples][build-script-examples] page
 the [conditional compilation][conditional-compilation-example] example.
 
diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md
index 12d0816ee..d1ee3f9f0 100644
--- a/src/doc/src/reference/unstable.md
+++ b/src/doc/src/reference/unstable.md
@@ -98,7 +98,6 @@ For the latest nightly, see the [nightly version] of this page.
     * [artifact dependencies](#artifact-dependencies) --- Allow build artifacts to be included into other build artifacts and build them for different targets.
     * [Edition 2024](#edition-2024) — Adds support for the 2024 Edition.
     * [Profile `trim-paths` option](#profile-trim-paths-option) --- Control the sanitization of file paths in build outputs.
-    * [`[lints.cargo]`](#lintscargo) --- Allows configuring lints for Cargo.
 * Information and metadata
     * [Build-plan](#build-plan) --- Emits JSON information on which commands will be run.
     * [unit-graph](#unit-graph) --- Emits JSON for Cargo's internal graph structure.
@@ -1522,27 +1521,6 @@ cargo-features = ["open-namespaces"]
 # ...
 ```
 
-## `[lints.cargo]`
-
-* Tracking Issue: [#12235](https://github.com/rust-lang/cargo/issues/12235)
-
-A new `lints` tool table for `cargo` that can be used to configure lints emitted
-by `cargo` itself when `-Zcargo-lints` is used
-```toml
-[lints.cargo]
-implicit-features = "warn"
-```
-
-This will work with
-[RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html):
-```toml
-[workspace.lints.cargo]
-implicit-features = "warn"
-
-[lints]
-workspace = true
-```
-
 # Stabilized and removed features
 
 ## Compile progress


Test patch:
diff --git a/tests/testsuite/artifact_dep.rs b/tests/testsuite/artifact_dep.rs
index 7194b4a61..d4b7d6cf5 100644
--- a/tests/testsuite/artifact_dep.rs
+++ b/tests/testsuite/artifact_dep.rs
@@ -1,7 +1,7 @@
 //! Tests specific to artifact dependencies, designated using
 //! the new `dep = { artifact = "bin", … }` syntax in manifests.
 
-use cargo_test_support::compare;
+use cargo_test_support::compare::match_exact;
 use cargo_test_support::registry::{Package, RegistryBuilder};
 use cargo_test_support::{
     basic_bin_manifest, basic_manifest, cross_compile, project, publish, registry, rustc_host,
@@ -593,9 +593,9 @@ fn build_script_with_bin_artifacts() {
         .run();
 
     let build_script_output = build_script_output_string(&p, "foo");
-    // we need the binary directory for this artifact along with all binary paths
+    let msg = "we need the binary directory for this artifact along with all binary paths";
     if cfg!(target_env = "msvc") {
-        compare::assert_match_exact(
+        match_exact(
             "[..]/artifact/bar-[..]/bin/baz.exe\n\
              [..]/artifact/bar-[..]/staticlib/bar-[..].lib\n\
              [..]/artifact/bar-[..]/cdylib/bar.dll\n\
@@ -603,9 +603,13 @@ fn build_script_with_bin_artifacts() {
              [..]/artifact/bar-[..]/bin/bar.exe\n\
              [..]/artifact/bar-[..]/bin/bar.exe",
             &build_script_output,
+            msg,
+            "",
+            None,
         )
+        .unwrap();
     } else {
-        compare::assert_match_exact(
+        match_exact(
             "[..]/artifact/bar-[..]/bin/baz-[..]\n\
              [..]/artifact/bar-[..]/staticlib/libbar-[..].a\n\
              [..]/artifact/bar-[..]/cdylib/[..]bar.[..]\n\
@@ -613,7 +617,11 @@ fn build_script_with_bin_artifacts() {
              [..]/artifact/bar-[..]/bin/bar-[..]\n\
              [..]/artifact/bar-[..]/bin/bar-[..]",
             &build_script_output,
+            msg,
+            "",
+            None,
         )
+        .unwrap();
     }
 
     assert!(
@@ -775,22 +783,31 @@ fn build_script_with_selected_dashed_bin_artifact_and_lib_true() {
         .run();
 
     let build_script_output = build_script_output_string(&p, "foo");
-    // we need the binary directory for this artifact and the binary itself
+    let msg = "we need the binary directory for this artifact and the binary itself";
+
     if cfg!(target_env = "msvc") {
-        compare::assert_match_exact(
+        cargo_test_support::compare::match_exact(
             &format!(
                 "[..]/artifact/bar-baz-[..]/bin\n\
                  [..]/artifact/bar-baz-[..]/bin/baz_suffix{}",
                 std::env::consts::EXE_SUFFIX,
             ),
             &build_script_output,
-        );
+            msg,
+            "",
+            None,
+        )
+        .unwrap();
     } else {
-        compare::assert_match_exact(
+        cargo_test_support::compare::match_exact(
             "[..]/artifact/bar-baz-[..]/bin\n\
         [..]/artifact/bar-baz-[..]/bin/baz_suffix-[..]",
             &build_script_output,
-        );
+            msg,
+            "",
+            None,
+        )
+        .unwrap();
     }
 
     assert!(
@@ -1740,7 +1757,14 @@ fn allow_dep_renames_with_multiple_versions() {
         .with_stderr_contains("[COMPILING] foo [..]")
         .run();
     let build_script_output = build_script_output_string(&p, "foo");
-    compare::assert_match_exact("0.5.0\n1.0.0", &build_script_output);
+    match_exact(
+        "0.5.0\n1.0.0",
+        &build_script_output,
+        "build script output",
+        "",
+        None,
+    )
+    .unwrap();
 }
 
 #[cargo_test]
@@ -3216,18 +3240,26 @@ fn build_only_specified_artifact_library() {
         .cargo("build -Z bindeps")
         .masquerade_as_nightly_cargo(&["bindeps"])
         .run();
-    compare::assert_match_exact(
+    match_exact(
         "cdylib present: true\nstaticlib present: false",
         &build_script_output_string(&cdylib, "foo"),
-    );
+        "build script output",
+        "",
+        None,
+    )
+    .unwrap();
 
     let staticlib = create_project("staticlib");
     staticlib
         .cargo("build -Z bindeps")
         .masquerade_as_nightly_cargo(&["bindeps"])
         .run();
-    compare::assert_match_exact(
+    match_exact(
         "cdylib present: false\nstaticlib present: true",
         &build_script_output_string(&staticlib, "foo"),
-    );
+        "build script output",
+        "",
+        None,
+    )
+    .unwrap();
 }
diff --git a/tests/testsuite/config.rs b/tests/testsuite/config.rs
index 8cd86ae0a..2ad81486d 100644
--- a/tests/testsuite/config.rs
+++ b/tests/testsuite/config.rs
@@ -6,7 +6,7 @@ use cargo::util::context::{
 };
 use cargo::CargoResult;
 use cargo_test_support::compare;
-use cargo_test_support::{paths, project, symlink_supported, t};
+use cargo_test_support::{panic_error, paths, project, symlink_supported, t};
 use cargo_util_schemas::manifest::TomlTrimPaths;
 use cargo_util_schemas::manifest::TomlTrimPathsValue;
 use cargo_util_schemas::manifest::{self as cargo_toml, TomlDebugInfo, VecStringOrBool as VSOB};
@@ -222,7 +222,14 @@ pub fn assert_error<E: Borrow<anyhow::Error>>(error: E, msgs: &str) {
         })
         .collect::<Vec<_>>()
         .join("\n\n");
-    compare::assert_match_exact(msgs, &causes);
+    assert_match(msgs, &causes);
+}
+
+#[track_caller]
+pub fn assert_match(expected: &str, actual: &str) {
+    if let Err(e) = compare::match_exact(expected, actual, "output", "", None) {
+        panic_error("", e);
+    }
 }
 
 #[cargo_test]
@@ -290,7 +297,7 @@ f1 = 1
     let expected = "\
 [WARNING] `[ROOT]/.cargo/config` is deprecated in favor of `config.toml`
 [NOTE] if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`";
-    compare::assert_match_exact(expected, &output);
+    assert_match(expected, &output);
 }
 
 #[cargo_test]
@@ -316,7 +323,7 @@ f1 = 1
 
     // It should NOT have warned for the symlink.
     let output = read_output(gctx);
-    compare::assert_match_exact("", &output);
+    assert_match("", &output);
 }
 
 #[cargo_test]
@@ -342,7 +349,7 @@ f1 = 1
 
     // It should NOT have warned for the symlink.
     let output = read_output(gctx);
-    compare::assert_match_exact("", &output);
+    assert_match("", &output);
 }
 
 #[cargo_test]
@@ -368,7 +375,7 @@ f1 = 1
 
     // It should NOT have warned for this situation.
     let output = read_output(gctx);
-    compare::assert_match_exact("", &output);
+    assert_match("", &output);
 }
 
 #[cargo_test]
@@ -398,7 +405,7 @@ f1 = 2
     let expected = "\
 [WARNING] both `[..]/.cargo/config` and `[..]/.cargo/config.toml` exist. Using `[..]/.cargo/config`
 ";
-    compare::assert_match_exact(expected, &output);
+    assert_match(expected, &output);
 }
 
 #[cargo_test]
@@ -432,7 +439,7 @@ unused = 456
     let expected = "\
 warning: unused config key `S.unused` in `[..]/.cargo/config.toml`
 ";
-    compare::assert_match_exact(expected, &output);
+    assert_match(expected, &output);
 }
 
 #[cargo_test]
diff --git a/tests/testsuite/config_cli.rs b/tests/testsuite/config_cli.rs
index f8dcb0073..1b90d58b9 100644
--- a/tests/testsuite/config_cli.rs
+++ b/tests/testsuite/config_cli.rs
@@ -1,10 +1,10 @@
 //! Tests for the --config CLI option.
 
 use super::config::{
-    assert_error, read_output, write_config_at, write_config_toml, GlobalContextBuilder,
+    assert_error, assert_match, read_output, write_config_at, write_config_toml,
+    GlobalContextBuilder,
 };
 use cargo::util::context::Definition;
-use cargo_test_support::compare;
 use cargo_test_support::paths;
 use std::{collections::HashMap, fs};
 
@@ -344,7 +344,7 @@ fn unused_key() {
     let expected = "\
 warning: unused config key `build.unused` in `--config cli option`
 ";
-    compare::assert_match_exact(expected, &output);
+    assert_match(expected, &output);
 }
 
 #[cargo_test]
diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs
index 24c253c55..63f318877 100644
--- a/tests/testsuite/registry.rs
+++ b/tests/testsuite/registry.rs
@@ -3833,3 +3833,43 @@ fn builtin_source_replacement() {
         )
         .run();
 }
+
+#[cargo_test]
+fn builtin_source_replacement_no_vendor_error() {
+    // errors for builtin source replacement of crates.io
+    // should not mention outdated vendor dependencies
+    let server = RegistryBuilder::new().build();
+
+    let p = project()
+        .file(
+            "Cargo.toml",
+            r#"
+                [package]
+                name = "foo"
+                version = "0.0.1"
+                edition = "2021"
+
+                [dependencies]
+                dep = "0.2.0"
+            "#,
+        )
+        .file("src/main.rs", "fn main() {}")
+        .build();
+
+    let pkg = Package::new("dep", "0.1.0");
+    pkg.publish();
+
+    p.cargo("check -v")
+        .replace_crates_io(&server.index_url())
+        .with_status(101)
+        .with_stderr(
+            "\
+[UPDATING] [..] index
+[ERROR] failed to select a version for the requirement `dep = \"^0.2.0\"`
+candidate versions found which didn't match: 0.1.0
+location searched: crates.io index
+required by package `foo v0.0.1 ([..])`
+",
+        )
+        .run();
+}