rust-lang / rust-lang/rust

Name resolution of `rustc_allow_incoherent_impl` methods affected by mention of dependency

Open
#149,347 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-crate-compat A-crates A-method-lookup A-no_std C-bug T-compiler T-lang
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I'm not sure if this is a bug or not.

The #[rustc_allow_incoherent_impl] attribute is an internal attribute which seems to allow one crate to define inherent methods on types defined in another crate. It's used to, for instance, define methods on str that require allocation, by doing so in the alloc crate.

Methods defined with #[rustc_allow_incoherent_impl] has strange name resolution behavior.

In the below code, note that to_lowercase is a #[rustc_allow_incoherent_impl] method defined in the alloc crate.

dep/src/lib.rs

// Notably does NOT have #![no_std]
pub fn something() {}

src/lib.rs

#![no_std]

pub fn foo() {
    let _ = "abc".to_lowercase();
}

pub fn bar() {
    // Deleting this makes the code stop compiling
    dep::something();
}

The above code compiles. However, deleting the dep::something(); call causes the code to stop compiling, saying that the to_lowercase method is not found. The code also compiles when replacing dep::something(); with use dep;.

That is, methods on str that are defined in alloc are available to be called in a no_std crate as soon as that crate mentions a dependency that has access to alloc.

This behavior seems wrong to me.

Additionally, it is possible to write code such that calling a function in a dependency can cause code in an unrelated function to stop compiling or change run time behavior. For example:

(dep/src/lib.rs same as above)
src/lib.rs

#![no_std]

trait Trait {
    fn to_lowercase(&self) -> i32 {
        1
    }
}
impl Trait for str {}

pub fn foo() {
    let _: i32 = "abc".to_lowercase();
}

pub fn bar() {
    // Delete this to make the code compile
    dep::something();
}

Also note that, in both versions of the code, the same behavior happens if we add #![no_std] and extern crate alloc; to dep/src/lib.rs, which is a scenario more likely to occur in real code.

Notably, the thing that matters is whether you mention the dependency or not. It doesn't matter whether the dependency in Cargo.toml or not.

Meta

rustc --version --verbose:

rustc 1.93.0-nightly (80d8f292d 2025-11-25)
binary: rustc
commit-hash: 80d8f292d82d735f83417221dd63b0dd2bbb8dd2
commit-date: 2025-11-25
host: aarch64-apple-darwin
release: 1.93.0-nightly
LLVM version: 21.1.5

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.

Research direction

Reproduce the behavior using dep/src/lib.rs and src/lib.rs, compiling the examples with and without the dep::something() call or use dep;. Compare method resolution for the incoherent alloc method and the local Trait implementation, using the reported rustc 1.93.0-nightly version. Done means dependency mention no longer changes whether unrelated method calls compile or alter their resolution.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.