rust-lang / rust-lang/rust

`#[no_link]` attribute does not prevent crate linking

Open
#152,854 20 comments 0 reactions 1 assignee View on GitHub

@petrochenkov is already working on this.

Since Feb 23, 2026.

A-linkage C-bug P-low regression-from-stable-to-stable T-compiler
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

View all comments

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.