Skip to content

Add [hints] table in Cargo.toml, and a hints.mostly-unused hint #15673

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
25 changes: 25 additions & 0 deletions crates/cargo-util-schemas/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@
}
]
},
"hints": {
"anyOf": [
{
"$ref": "#/$defs/Hints"
},
{
"type": "null"
}
]
},
"workspace": {
"anyOf": [
{
Expand Down Expand Up @@ -998,6 +1008,21 @@
"$ref": "#/$defs/TomlValue"
}
},
"Hints": {
"type": "object",
"properties": {
"mostly-unused": {
"anyOf": [
{
"$ref": "#/$defs/TomlValue"
},
{
"type": "null"
}
]
}
}
},
"TomlWorkspace": {
"type": "object",
"properties": {
Expand Down
13 changes: 13 additions & 0 deletions crates/cargo-util-schemas/src/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub struct TomlManifest {
pub build_dependencies2: Option<BTreeMap<PackageName, InheritableDependency>>,
pub target: Option<BTreeMap<String, TomlPlatform>>,
pub lints: Option<InheritableLints>,
pub hints: Option<Hints>,

pub workspace: Option<TomlWorkspace>,
pub profile: Option<TomlProfiles>,
Expand Down Expand Up @@ -85,6 +86,7 @@ impl TomlManifest {
.map(|_| "build-dependencies"),
self.target.as_ref().map(|_| "target"),
self.lints.as_ref().map(|_| "lints"),
self.hints.as_ref().map(|_| "hints"),
]
.into_iter()
.flatten()
Expand Down Expand Up @@ -1641,6 +1643,17 @@ pub enum TomlLintLevel {
Allow,
}

#[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct Hints {
#[cfg_attr(
feature = "unstable-schema",
schemars(with = "Option<TomlValueWrapper>")
)]
pub mostly_unused: Option<toml::Value>,
}

#[derive(Copy, Clone, Debug)]
pub struct InvalidCargoFeatures {}

Expand Down
43 changes: 38 additions & 5 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,11 +1135,27 @@ fn build_base_args(
strip,
rustflags: profile_rustflags,
trim_paths,
hint_mostly_unused,
hint_mostly_unused: profile_hint_mostly_unused,
..
} = unit.profile.clone();
let hints = unit.pkg.hints().cloned().unwrap_or_default();
let test = unit.mode.is_any_test();

let warn = |msg: &str| {
bcx.gctx.shell().warn(format!(
"{}@{}: {msg}",
unit.pkg.package_id().name(),
unit.pkg.package_id().version()
))
};
let unit_capped_warn = |msg: &str| {
if unit.show_warnings(bcx.gctx) {
warn(msg)
} else {
Ok(())
}
};

cmd.arg("--crate-name").arg(&unit.target.crate_name());

let edition = unit.target.edition();
Expand Down Expand Up @@ -1326,13 +1342,30 @@ fn build_base_args(
opt(cmd, "-C", "incremental=", Some(dir));
}

if hint_mostly_unused {
let pkg_hint_mostly_unused = match hints.mostly_unused {
None => None,
Some(toml::Value::Boolean(b)) => Some(b),
Some(v) => {
unit_capped_warn(&format!(
"ignoring unsupported value type ({}) for 'hints.mostly-unused', which expects a boolean",
v.type_str()
))?;
None
}
};
if profile_hint_mostly_unused
.or(pkg_hint_mostly_unused)
.unwrap_or(false)
{
if bcx.gctx.cli_unstable().profile_hint_mostly_unused {
cmd.arg("-Zhint-mostly-unused");
} else {
bcx.gctx
.shell()
.warn("ignoring 'hint-mostly-unused' profile option, pass `-Zprofile-hint-mostly-unused` to enable it")?;
if profile_hint_mostly_unused.is_some() {
// Profiles come from the top-level unit, so we don't use `unit_capped_warn` here.
warn("ignoring 'hint-mostly-unused' profile option, pass `-Zprofile-hint-mostly-unused` to enable it")?;
} else if pkg_hint_mostly_unused.is_some() {
unit_capped_warn("ignoring 'hints.mostly-unused', pass `-Zprofile-hint-mostly-unused` to enable it")?;
}
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::sync::Arc;

use anyhow::Context as _;
use cargo_util_schemas::manifest::RustVersion;
use cargo_util_schemas::manifest::{TomlManifest, TomlProfiles};
use cargo_util_schemas::manifest::{Hints, TomlManifest, TomlProfiles};
use semver::Version;
use serde::ser;
use serde::Serialize;
Expand Down Expand Up @@ -90,6 +90,7 @@ pub struct Manifest {
metabuild: Option<Vec<String>>,
resolve_behavior: Option<ResolveBehavior>,
lint_rustflags: Vec<String>,
hints: Option<Hints>,
embedded: bool,
}

Expand Down Expand Up @@ -521,6 +522,7 @@ impl Manifest {
metabuild: Option<Vec<String>>,
resolve_behavior: Option<ResolveBehavior>,
lint_rustflags: Vec<String>,
hints: Option<Hints>,
embedded: bool,
) -> Manifest {
Manifest {
Expand Down Expand Up @@ -551,6 +553,7 @@ impl Manifest {
metabuild,
resolve_behavior,
lint_rustflags,
hints,
embedded,
}
}
Expand Down Expand Up @@ -668,6 +671,10 @@ impl Manifest {
self.lint_rustflags.as_slice()
}

pub fn hints(&self) -> Option<&Hints> {
self.hints.as_ref()
}

pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
Manifest {
summary: self.summary.map_source(to_replace, replace_with),
Expand Down
10 changes: 9 additions & 1 deletion src/cargo/core/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::rc::Rc;
use std::time::{Duration, Instant};

use anyhow::Context as _;
use cargo_util_schemas::manifest::RustVersion;
use cargo_util_schemas::manifest::{Hints, RustVersion};
use curl::easy::Easy;
use curl::multi::{EasyHandle, Multi};
use lazycell::LazyCell;
Expand Down Expand Up @@ -95,6 +95,8 @@ pub struct SerializedPackage {
metabuild: Option<Vec<String>>,
default_run: Option<String>,
rust_version: Option<RustVersion>,
#[serde(skip_serializing_if = "Option::is_none")]
hints: Option<Hints>,
}

impl Package {
Expand Down Expand Up @@ -172,6 +174,11 @@ impl Package {
self.manifest().rust_version()
}

/// Gets the package's hints.
pub fn hints(&self) -> Option<&Hints> {
self.manifest().hints()
}

/// Returns `true` if the package uses a custom build script for any target.
pub fn has_custom_build(&self) -> bool {
self.targets().iter().any(|t| t.is_custom_build())
Expand Down Expand Up @@ -241,6 +248,7 @@ impl Package {
publish: self.publish().as_ref().cloned(),
default_run: self.manifest().default_run().map(|s| s.to_owned()),
rust_version: self.rust_version().cloned(),
hints: self.hints().cloned(),
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/cargo/core/profiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) {
profile.trim_paths = Some(trim_paths.clone());
}
if let Some(hint_mostly_unused) = toml.hint_mostly_unused {
profile.hint_mostly_unused = hint_mostly_unused;
profile.hint_mostly_unused = Some(hint_mostly_unused);
}
profile.strip = match toml.strip {
Some(StringOrBool::Bool(true)) => Strip::Resolved(StripInner::Named("symbols".into())),
Expand Down Expand Up @@ -629,8 +629,8 @@ pub struct Profile {
// remove when `-Ztrim-paths` is stablized
#[serde(skip_serializing_if = "Option::is_none")]
pub trim_paths: Option<TomlTrimPaths>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub hint_mostly_unused: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub hint_mostly_unused: Option<bool>,
}

impl Default for Profile {
Expand All @@ -652,7 +652,7 @@ impl Default for Profile {
strip: Strip::Deferred(StripInner::None),
rustflags: vec![],
trim_paths: None,
hint_mostly_unused: false,
hint_mostly_unused: None,
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ fn normalize_toml(
build_dependencies2: None,
target: None,
lints: None,
hints: None,
workspace: original_toml.workspace.clone().or_else(|| {
// Prevent looking for a workspace by `read_manifest_from_str`
is_embedded.then(manifest::TomlWorkspace::default)
Expand Down Expand Up @@ -559,6 +560,8 @@ fn normalize_toml(
lints,
});

normalized_toml.hints = original_toml.hints.clone();

normalized_toml.badges = original_toml.badges.clone();
} else {
if let Some(field) = original_toml.requires_package().next() {
Expand Down Expand Up @@ -1608,6 +1611,8 @@ pub fn to_real_manifest(
.unwrap_or(&default),
)?;

let hints = normalized_toml.hints.clone();

let metadata = ManifestMetadata {
description: normalized_package
.normalized_description()
Expand Down Expand Up @@ -1799,6 +1804,7 @@ pub fn to_real_manifest(
metabuild,
resolve_behavior,
rustflags,
hints,
is_embedded,
);
if manifest
Expand Down Expand Up @@ -3050,6 +3056,7 @@ fn prepare_toml_for_publish(
None => None,
},
lints: me.lints.clone(),
hints: me.hints.clone(),
workspace: None,
profile: me.profile.clone(),
patch: None,
Expand Down
20 changes: 20 additions & 0 deletions src/doc/src/reference/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Every manifest file consists of the following sections:
* [`[badges]`](#the-badges-section) --- Badges to display on a registry.
* [`[features]`](features.md) --- Conditional compilation features.
* [`[lints]`](#the-lints-section) --- Configure linters for this package.
* [`[hints]`](#the-hints-section) --- Provide hints for compiling this package.
* [`[patch]`](overriding-dependencies.md#the-patch-section) --- Override dependencies.
* [`[replace]`](overriding-dependencies.md#the-replace-section) --- Override dependencies (deprecated).
* [`[profile]`](profiles.md) --- Compiler settings and optimizations.
Expand Down Expand Up @@ -565,6 +566,25 @@ As for dependents, Cargo suppresses lints from non-path dependencies with featur

> **MSRV:** Respected as of 1.74

## The `[hints]` section

The `[hints]` section allows specifying hints for compiling this crate, which
crates depending on this one will use by default but may override. Hints are,
by design, always safe for Cargo to ignore; if Cargo encounters a hint it
doesn't understand, or a hint it understands but with a value it doesn't
understand, it will warn, but not error.

Individual hints may have an associated unstable feature gate that you need to
pass in order to apply the configuration they specify, but if you don't specify
that unstable feature gate, you will again get only a warning, not an error.

There are no stable hints at this time. See the [hint-mostly-unused
documentation](unstable.md#profile-hint-mostly-unused-option) for information
on an unstable hint.

> **MSRV:** Specifying hints does not impact MSRV. Older versions of Cargo will
> ignore hints with a warning, but will not error.

## The `[badges]` section

The `[badges]` section is for specifying status badges that can be displayed
Expand Down
12 changes: 12 additions & 0 deletions src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,18 @@ introduction of this feature will give an "unused manifest key" warning, but
will otherwise function without erroring. This allows using the hint in a
crate's `Cargo.toml` without mandating the use of a newer Cargo to build it.

A crate can also provide this hint automatically for crates that depend on it,
using the `[hints]` table (which will likewise be ignored by older Cargo):

```toml
[hints]
mostly-unused = true
```

This will cause the crate to default to hint-mostly-unused, unless overridden
via `profile`, which takes precedence, and which can only be specified in the
top-level crate being built.

## rustdoc-map
* Tracking Issue: [#8296](https://github.com/rust-lang/cargo/issues/8296)

Expand Down
Loading
Loading