Repository navigation
#[no_link] attribute does not prevent crate linking #152854
Description
Problem: #[no_link] does not prevent an extern crate from being linked.
Steps to reproduce:
macro_crate/Cargo.toml:
[package]
name = "macro_crate"
version = "0.1.0"
edition = "2021"macro_crate/src/lib.rs:
#[macro_export]
macro_rules! square {
($x:expr) => {
$x * $x
};
}
pub fn add(x: i32, y: i32) -> i32 {
x + y
}Cargo.toml:
[package]
name = "no_link_bug"
version = "0.1.0"
edition = "2024"
[dependencies]
macro_crate = { path = "../macro_crate" }src/main.rs:
#[no_link]
extern crate macro_crate;
fn main() {
let num = 4;
let squared = macro_crate::square!(num);
println!("{} squared is {}", num, squared);
let sum = macro_crate::add(1, 2);
println!("1 + 2 = {}", sum);
}Expected behavior:
The build should fail with a linker error, for example:
rust-lld: error: undefined symbol: macro_crate::add::hd706c5be871dff6f
Actual behavior:
The build succeeds and produces a binary.
Meta:
rustc 1.95.0-nightly (c04308580 2026-02-18)
binary: rustc
commit-hash: c043085801b7a884054add21a94882216df5971c
commit-date: 2026-02-18
host: x86_64-unknown-linux-gnu
release: 1.95.0-nightly
LLVM version: 22.1.0
cargo 1.95.0-nightly (ce69df6f7 2026-02-12)
Linux x86_64
Verbose build output:
Verbose output
RUST_BACKTRACE=1 cargo build -vv
Compiling macro_crate v0.1.0 (/home/mmoro/Projects/no_link_bug/macro_crate)
Running `CARGO=/home/mmoro/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo CARGO_CRATE_NAME=macro_crate CARGO_MANIFEST_DIR=/home/mmoro/Projects/no_link_bug/macro_crate CARGO_MANIFEST_PATH=/home/mmoro/Projects/no_link_bug/macro_crate/Cargo.toml CARGO_PKG_AUTHORS='' CARGO_PKG_DESCRIPTION='' CARGO_PKG_HOMEPAGE='' CARGO_PKG_LICENSE='' CARGO_PKG_LICENSE_FILE='' CARGO_PKG_NAME=macro_crate CARGO_PKG_README='' CARGO_PKG_REPOSITORY='' CARGO_PKG_RUST_VERSION='' CARGO_PKG_VERSION=0.1.0 CARGO_PKG_VERSION_MAJOR=0 CARGO_PKG_VERSION_MINOR=1 CARGO_PKG_VERSION_PATCH=0 CARGO_PKG_VERSION_PRE='' LD_LIBRARY_PATH='/home/mmoro/Projects/no_link_bug/target/debug/deps:/home/mmoro/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib' /home/mmoro/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc --crate-name macro_crate --edition=2021 macro_crate/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=192 --crate-type rlib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=1ffd961baa1102b0 -C extra-filename=-c0993a15f8871f25 --out-dir /home/mmoro/Projects/no_link_bug/target/debug/deps -C incremental=/home/mmoro/Projects/no_link_bug/target/debug/incremental -L dependency=/home/mmoro/Projects/no_link_bug/target/debug/deps`
Compiling no_link_bug v0.1.0 (/home/mmoro/Projects/no_link_bug)
Running `CARGO=/home/mmoro/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo CARGO_BIN_NAME=no_link_bug CARGO_CRATE_NAME=no_link_bug CARGO_MANIFEST_DIR=/home/mmoro/Projects/no_link_bug CARGO_MANIFEST_PATH=/home/mmoro/Projects/no_link_bug/Cargo.toml CARGO_PKG_AUTHORS='' CARGO_PKG_DESCRIPTION='' CARGO_PKG_HOMEPAGE='' CARGO_PKG_LICENSE='' CARGO_PKG_LICENSE_FILE='' CARGO_PKG_NAME=no_link_bug CARGO_PKG_README='' CARGO_PKG_REPOSITORY='' CARGO_PKG_RUST_VERSION='' CARGO_PKG_VERSION=0.1.0 CARGO_PKG_VERSION_MAJOR=0 CARGO_PKG_VERSION_MINOR=1 CARGO_PKG_VERSION_PATCH=0 CARGO_PKG_VERSION_PRE='' CARGO_PRIMARY_PACKAGE=1 LD_LIBRARY_PATH='/home/mmoro/Projects/no_link_bug/target/debug/deps:/home/mmoro/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib' /home/mmoro/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc --crate-name no_link_bug --edition=2024 src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=192 --crate-type bin --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=6bf287f543d40f7f -C extra-filename=-838203c1bd20a69b --out-dir /home/mmoro/Projects/no_link_bug/target/debug/deps -C incremental=/home/mmoro/Projects/no_link_bug/target/debug/incremental -L dependency=/home/mmoro/Projects/no_link_bug/target/debug/deps --extern macro_crate=/home/mmoro/Projects/no_link_bug/target/debug/deps/libmacro_crate-c0993a15f8871f25.rlib`
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s
My thoughts:
When rustc is invoked with --extern macro_crate=…/*.rlib, the crate is initially loaded as Unconditional. Later, when the compiler sees #[no_link] extern crate macro_crate, it attempts to downgrade it to MacrosOnly. However, maybe_resolve_crate uses cmp::max when updating the crate’s dep_kind, so the Unconditional status is retained. As a result, the crate is still linked, and functions like macro_crate::add are available, causing the build to succeed rather than produce a linker error.
Activity
eggyal commentedon Feb 19, 2026
Appears to be a regression in 1.91.
On 1.90, I see the following:
@rustbot label +A-linkage +E-needs-bisection +T-compiler +regression-from-stable-to-stable -needs-triage
rustbot commentedon Feb 19, 2026
Error: Unknown labels: E-needs-bisect
Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #triagebot on Zulip.
bjorn3 commentedon Feb 19, 2026
addwas likely cross-crate inlined, somacro_cratehappened to not actually be necessary at link time. In any case#[no_link]is very fragile as there are no checks that you are not using anything from such a crate other than macros. I did be in favor of deprecating and removing it.petrochenkov commentedon Feb 19, 2026
Please, check the linker command line to make sure that
macro_crateis indeed linked.fn addmay be opportunistically inlined at MIR level because it's very small.--externby itself doesn't cause any crate loading, it only specifies where to find the crate if it's actually used.eggyal commentedon Feb 19, 2026
petrochenkov commentedon Feb 19, 2026
It's a pre-Rust 1.0 attribute that was stabilized accidentally.
IIRC it was used for compiler plugins originally.
eggyal commentedon Feb 19, 2026
I guess a crater run to guage how much removal might impact the ecosystem, and then nominate for lang discussion?
2 remaining items
martonmoro commentedon Feb 19, 2026
In the MIR it shows
also the symbol is in the text section
0000000000014400 T _RNvCsk6r9O4cPmFO_11macro_crate3addDoes this show that it is not being inlined? Should I run anything else?
bjorn3 commentedon Feb 19, 2026
Is that in libmacro_crate.rlib or the object file of the executable? If the latter, it did actually get cross-crate inlined. Cross-crate inlining only ensures that the function is codegened as private function in the crates that use the function. It is then up to LLVM to actually inline the call, which doesn't happen when optimizations are disabled.
martonmoro commentedon Feb 19, 2026
aah, it's from the executable.
martonmoro commentedon Feb 19, 2026
the part that I don't understand is that when I add
#[inline(never)]and runRUSTC_LOG=rustc_codegen_ssa::back::link=info cargo buildthis is present in the linker arguments:
libmacro_crate-c0993a15f8871f25.rlibnightly and 1.90.0 comparison
building with 1.90.0 this is absent
bjorn3 commentedon Feb 19, 2026
#152856 should be suitable for doing a crater run on removing
#[no_link]I think.petrochenkov commentedon Feb 20, 2026
In any case, if
libmacro_crate-c0993a15f8871f25.rlibappears on the linker command line, then something legitimately regressed, and may potentially cause other issues. It would be good to figure it out, even ifno_linkis removed eventually.eggyal commentedon Feb 20, 2026
JonathanBrouwer commentedon Feb 20, 2026
Huh that's interesting, I'll take a look at this later today
JonathanBrouwer commentedon Feb 20, 2026
I checked #145085, both before and after the PR
cargo buildsucceeds (so the bug is there), so this PR is not the regressing PReggyal commentedon Feb 20, 2026
Agh, apologies!
bisection
I had the right nightly, but must have messed up the
git bisect. I've double checked this time, and the regression is definitely in #144793 cc @petrochenkov @davidtwcopetrochenkov commentedon Feb 23, 2026
Minimized without cargo.
Whether
libmacro_crate.rlibappears on linker's command line depends on the presence of the macro call.petrochenkov commentedon Feb 23, 2026
Fix: petrochenkov@ca89c6e
I'm not too interested in actually submitting it, introducing this kind of additional overriding hierarchy doesn't seem right.
It would be better to just turn
#[no_link]into noop and deprecate it.