Skip to content

Conversation

@petrochenkov
Copy link
Contributor

@petrochenkov petrochenkov commented Oct 22, 2025

So in cross-crate scenarios they can work in the same way as in crate-local scenarios.

Change Description: #147984 (comment)

Resurrection of #114682.
One of unblocking steps for #145108.
Fixes #36837.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Oct 22, 2025
@rustbot
Copy link
Collaborator

rustbot commented Oct 22, 2025

r? @jdonszelmann

rustbot has assigned @jdonszelmann.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@petrochenkov
Copy link
Contributor Author

@bors try

rust-bors bot added a commit that referenced this pull request Oct 22, 2025
resolve: Preserve ambiguous glob reexports in crate metadata
@rust-bors

This comment has been minimized.

@petrochenkov petrochenkov added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 22, 2025
@petrochenkov
Copy link
Contributor Author

cc @LorrensP-2158466 @bvanjoi

@rust-bors
Copy link

rust-bors bot commented Oct 22, 2025

☀️ Try build successful (CI)
Build commit: b4c5508 (b4c55082edd8dec08ce8af276d7054d9c4db20c4, parent: f5e2df741b4a9820a7579f0c8eccc951706a8782)

@petrochenkov
Copy link
Contributor Author

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-147984 created and queued.
🤖 Automatically detected try build b4c5508
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🚧 Experiment pr-147984 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-147984 is completed!
📊 2312 regressed and 2 fixed (721923 total)
📊 1766 spurious results on the retry-regessed-list.txt, consider a retry1 if this is a significant amount.
📰 Open the summary report.

⚠️ If you notice any spurious failure please add them to the denylist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

Footnotes

  1. re-run the experiment with crates=https://crater-reports.s3.amazonaws.com/pr-147984/retry-regressed-list.txt

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Oct 24, 2025
@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 24, 2025
@petrochenkov
Copy link
Contributor Author

That's a lot of breakage.
Mostly from dependencies, including various version of openssl that we've seen previously.
I'll demote this error to always be reported as a lint in cross-crate scenarios, and then rerun crater.

@rustbot

This comment has been minimized.

@petrochenkov
Copy link
Contributor Author

@bors try

@craterbot run mode=check-only p=1 crates=https://crater-reports.s3.amazonaws.com/pr-147984/retry-regressed-list.txt

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Oct 24, 2025
resolve: Preserve ambiguous glob reexports in crate metadata
@petrochenkov petrochenkov added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 24, 2025
@rust-bors
Copy link

rust-bors bot commented Oct 24, 2025

☀️ Try build successful (CI)
Build commit: c6359cd (c6359cd3b4418e8472bae1a89c242796f2b86d56, parent: 75948c8bb3bd37f1e8ee20273a04edea4c1f84f8)

@petrochenkov
Copy link
Contributor Author

@craterbot
Copy link
Collaborator

👌 Experiment pr-147984-1 created and queued.
🤖 Automatically detected try build c6359cd
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@traviscross traviscross added the relnotes Marks issues that should be documented in the release notes of the next release. label Nov 10, 2025
@traviscross
Copy link
Contributor

cc @yaahc @rust-lang/lang-docs @rust-lang/fls

@petrochenkov
Copy link
Contributor Author

ping @jdonszelmann, this is blocking other work.
cc @b-naber maybe you could take over?

@jdonszelmann
Copy link
Contributor

@rustbot reroll

sorry, am not sure I can review this right now

@rustbot rustbot assigned SparrowLii and unassigned jdonszelmann Nov 21, 2025
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Nov 27, 2025
@bors

This comment was marked as resolved.

@petrochenkov
Copy link
Contributor Author

@yaahc This is now blocking #149195 as well.

@petrochenkov petrochenkov removed needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-t-lang Status: Awaiting decision from T-lang labels Dec 2, 2025
@yaahc
Copy link
Member

yaahc commented Dec 2, 2025

r? @yaahc

(self.arenas.new_res_binding(res, vis, span, expansion), ambig_kind)
});
// Record primary definitions.
match res {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: When I was reviewing this section I felt like there was a high signal to noise ratio with the way this match is structured. As far as I can tell the only difference between the different define_extern calls is the namespace argument. I'd recommend changing this match to evaluate to the namespace and pass that ns local into a single shared invocation of define_extern regardless of res defkind.

Especially with the new field changing the formatting to be one line per argument, its even more difficult now to visually tell what is different and what isn't between those invocations.

Feel free to ignore this one, just thought I'd share my experience.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can factor the define_extern calls into a closure.
I'd like to preserve the exhaustive match because of the bug!("unexpected resolution: {:?}", res) part.

self.build_reduced_graph_for_external_crate_res(child, parent_scope, i, None)
}
for (i, child) in
self.cstore().ambig_module_children_untracked(def_id, self.tcx.sess).enumerate()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be untracked?

I did some digging and as far as I can tell this is referring to how it's not being accessed through the query system unlike the module_children access above, that it'd break incremental compilation, and that it should only be called pre-HIR (during resolve). I'm not super familiar with the query system though or the later stages of resolution so I want to double check that I understand this properly.

My understanding is that this is satisfying the "should only be called" pre-HIR requirement because all of these ambig children are materialized into their appropriate scopes during early resolution and this untracked method is never called after that.

What I don't understand is how this would interact with incremental compilation and break things and what differences there are between the module children and ambig module children that make us only want to track calls to one of them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name resolution happens before incremental compilation starts, so we can just read things from CStore instead of using queries, see other uses of .cstore() in rustc_resolve.

Comment on lines +148 to +153
let node_id = match ambiguity_error.b1.0.kind {
NameBindingKind::Import { import, .. } => import.root_id,
NameBindingKind::Res(_) => CRATE_NODE_ID,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to make sure I understand why this changed.

My understanding is that previously we'd only hit this code path via ambiguity errors produced from glob imports in try_define_local. Now we can create them from the ambiguity_children of extern crates, but these only contain a simplified copy of the original import chain and the final res from the original nested set of namebindings. Since you couldn't reasonably recreate the original nested set of namebindings you instead construct a new namebinding from just the underlying Res which you mark as an ambiguity warning.

Let me know if that sounds right

The remaining question I have is how does the NodeId selected here impact the diagnostic we emit? From what I can tell the span in use is that of the outermost import in the re-export chain. I would assume that the diagnostic would be able to point to the external ambiguous pub use declaration but I'm not familiar enough with our diagnostic logic to know how the nodeid comes in. I tried poking around and it seems like it may impact the way the lints are buffered and emitted. I'd guess this might impact the order in which this warning is emitted relative to other diagnostics but I stopped digging when I saw that the rustc_dev_guide said that nodeid was being phased out. I'm guessing this is relatively inconsequential.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if that sounds right

Sounds right, some parts of the original chain are minimally preserved just to report nice diagnostics.

The remaining question I have is how does the NodeId selected here impact the diagnostic we emit?

It determines the placement of allow/warn/deny attributes.
CRATE_NODE_ID means that only crate level allow-warn-deny would work (other crates don't have node ids, so crate id here is used as a fallback).
The node id selection here is not good in general, it would be better to use some use-site node id here, but it's a larger change, and I wouldn't bother doing it in this PR.

// ambiguity error instead of a not found error.
glob_conflict::f(); //~ ERROR `f` is ambiguous
//~| WARN this was previously accepted
glob_conflict::glob::f(); //~ ERROR `f` is ambiguous
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly have no idea how this is resolving, the glob import this is resolving through looks like nonsense to me:

pub use m1::*;
pub use m2::*;
pub mod glob {
pub use *;
}

when I try to do this in a test crate it says "cannot export all crates". I wouldn't expect f to be in scope for re-exportation due to the mod glob {..} boundary. How does this work? I'm thoroughly stumped

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@P1n3appl3 pointed out that this is a 2015 edition thing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, use * on 2015 edition is just use crate::*.

Comment on lines +14 to +17
//~^ ERROR `C` is ambiguous
//~| ERROR `C` is ambiguous
//~| WARN this was previously accepted
//~| WARN this was previously accepted
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this emit so many duplicate warnings? It looks like theres two unique ones, the one for the local ambiguity and the one for the external ambiguity, but the stderr file looks like its emitting each of those twice for a total of four warnings. Why isn't this being prevented by the warning deduplication logic?

if !self.matches_previous_ambiguity_error(&ambiguity_error) {
// avoid duplicated span information to be emit out
self.ambiguity_errors.push(ambiguity_error);
}

Copy link
Contributor Author

@petrochenkov petrochenkov Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fn record_use_inner walks the import chain and reports an ambiguity at every step.
I think we could only report the first one (if it's an error).
I look at the PR introducing the deduplication logic, and I don't think the author really understood what they were doing, not sure why it doesn't deduplicate this specific case.
In any case, probably off-topic for this PR.

Upd: also record_use can run twice on the same "use", at least for imports (for other diagnostic reasons).

Comment on lines -14 to -17
// First, should this ambiguous item be omitted considering the maximum visibility
// of `issue_114682_2_extern::m::max` in the type namespace is only within the extern crate.
// Second, if we retain the ambiguous item of the extern crate, should it be treated
// as an ambiguous item within the local crate for the same reasoning?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you link to where the decision on these questions was made?

From my understanding of the PR it's looking like you went with

  1. no
  2. no

Is that right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Correct, seems to be the simplest and conservative choice.
  2. I don't quite understand the sentence, but it seems like the answer is "yes", because issue_114682_2_extern::max is indeed treated as ambiguous in this test (= local crate).

a.ext();
//^ FIXME: it should report `ext` not found because `SettingsExt`
// is an ambiguous item in `issue-114682-3-extern.rs`.
//~^ ERROR no method named `ext` found for type `u8` in the current scope
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've not yet looked into how ambiguous imports interact with which traits are in scope so the logic for this is unfamiliar to me but I find this behavior surprising. I would have expected this to report an ambiguity error while selecting the innermost1 candidate and continuing, not for it to block the selection of all three candidates in scope with no mention of ambiguity.

This doesn't seem like an ideal diagnostic experience. Is there some structural issue that makes it hard to identify and report that this error was caused by an interaction with ambiguious imports?

Footnotes

  1. I know this is a globvsglob/globvsexpanded issue where they're ambiguous within a single scope so I'm not sure innermost is accurate, but I don't remember off hand how the candidates for this kind of ambiguity are stored and its nearing the end of the day so I wanna get my first review pass posted rather than diving in more deeply.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a separate issue (#147992), there are several possible ways to address it, and the latest development can be found in #149058.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR and that PR combined will result in .ext() producing a compatibility warning about the method call being ambiguous.

use issue_114682_4_extern::*;

fn a() -> Result<i32, ()> { // FIXME: `Result` should be identified as an ambiguous item.
//~v ERROR type alias takes 1 generic argument but 2 generic arguments were supplied
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah see, this one picks one of the extern results and prints this error, that's how I'd expect things to work normally, the previous one with the traits in scope resolution was super inconsistent w/ my previous experience.

#[derive(Debug, TyEncodable, TyDecodable, HashStable)]
pub enum AmbigModChildKind {
GlobVsGlob,
GlobVsExpanded,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming this means logic should be able to preserve globvsexpanded ambiguities across crate boundaries but I don't see any tests exercising this logic. Can you add one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add a test.
In any case, cross-crate GlobVsExpanded is unnecessary and will be removed in #149681.

@yaahc
Copy link
Member

yaahc commented Dec 6, 2025

We won't be catching cases where the ambiguity comes from a dependency adding an item in a subsequent version. @nikomatsakis made a suggestion to lint anytime we glob export from two different crates, which I liked. Otherwise, we can at least catch cases where there is a known conflict at the time of writing the code.

@petrochenkov am I correct in understanding that https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#ambiguous-glob-reexports represents the def-site lint but not the second suggestion from niko quoted above?

@tmandry am I correct in assuming that lang doesn't consider adding the second lint you mentioned to be a blocker for this PR?

@tmandry
Copy link
Member

tmandry commented Dec 6, 2025

@yaahc Just checking you mean this one. Correct, I don't consider it a blocker.

nikomatsakis made a suggestion to lint anytime we glob export from two different crates, which I liked.

@yaahc
Copy link
Member

yaahc commented Dec 6, 2025

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 6, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 6, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

So in cross-crate scenarios they can work in the same way as in crate-local scenarios.
- Factor `define_extern` into a closure
- Add a test for cross-crate GlobVsExpanded ambiguity
@rustbot
Copy link
Collaborator

rustbot commented Dec 6, 2025

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@petrochenkov
Copy link
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-lang Relevant to the language team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

item_like_imports: Can "ambiguity error" items be reexported?