From 51f42d617e99dfaa790a55b44a68c28cc97f5ae1 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Fri, 24 Apr 2026 14:59:57 +0200 Subject: [PATCH 001/116] Add temporary scope to assert_eq and assert_ne This is a follow-up to https://github.com/rust-lang/rust/pull/155431 --- library/core/src/macros/mod.rs | 16 ++++++++-------- library/coretests/tests/macros.rs | 14 +++++++++++++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 08a12b6447e61..26a964a76c598 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -40,7 +40,7 @@ macro_rules! panic { #[rustc_diagnostic_item = "assert_eq_macro"] #[allow_internal_unstable(panic_internals)] macro_rules! assert_eq { - ($left:expr, $right:expr $(,)?) => { + ($left:expr, $right:expr $(,)?) => {{ match (&$left, &$right) { (left_val, right_val) => { if !(*left_val == *right_val) { @@ -52,8 +52,8 @@ macro_rules! assert_eq { } } } - }; - ($left:expr, $right:expr, $($arg:tt)+) => { + }}; + ($left:expr, $right:expr, $($arg:tt)+) => {{ match (&$left, &$right) { (left_val, right_val) => { if !(*left_val == *right_val) { @@ -65,7 +65,7 @@ macro_rules! assert_eq { } } } - }; + }}; } /// Asserts that two expressions are not equal to each other (using [`PartialEq`]). @@ -96,7 +96,7 @@ macro_rules! assert_eq { #[rustc_diagnostic_item = "assert_ne_macro"] #[allow_internal_unstable(panic_internals)] macro_rules! assert_ne { - ($left:expr, $right:expr $(,)?) => { + ($left:expr, $right:expr $(,)?) => {{ match (&$left, &$right) { (left_val, right_val) => { if *left_val == *right_val { @@ -108,8 +108,8 @@ macro_rules! assert_ne { } } } - }; - ($left:expr, $right:expr, $($arg:tt)+) => { + }}; + ($left:expr, $right:expr, $($arg:tt)+) => {{ match (&($left), &($right)) { (left_val, right_val) => { if *left_val == *right_val { @@ -121,7 +121,7 @@ macro_rules! assert_ne { } } } - }; + }}; } /// Asserts that an expression matches the provided pattern. diff --git a/library/coretests/tests/macros.rs b/library/coretests/tests/macros.rs index 9f73ebd253c3b..86419bb41e527 100644 --- a/library/coretests/tests/macros.rs +++ b/library/coretests/tests/macros.rs @@ -241,7 +241,19 @@ fn temporary_scope_introduction() { (assert_matches!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val)); (assert_matches!(*MutRefWithDrop(&mut val).0, 0, "msg"), std::mem::take(&mut val)); - (debug_assert_matches!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val)); (debug_assert_matches!(*MutRefWithDrop(&mut val).0, 0, "msg"), std::mem::take(&mut val)); + + (assert_eq!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val)); + (assert_eq!(*MutRefWithDrop(&mut val).0, 0, "msg"), std::mem::take(&mut val)); + (debug_assert_eq!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val)); + (debug_assert_eq!(*MutRefWithDrop(&mut val).0, 0, "msg"), std::mem::take(&mut val)); + + (assert_ne!(*MutRefWithDrop(&mut val).0, 1), std::mem::take(&mut val)); + (assert_ne!(*MutRefWithDrop(&mut val).0, 1, "msg"), std::mem::take(&mut val)); + (debug_assert_ne!(*MutRefWithDrop(&mut val).0, 1), std::mem::take(&mut val)); + (debug_assert_ne!(*MutRefWithDrop(&mut val).0, 1, "msg"), std::mem::take(&mut val)); + + (assert!(*MutRefWithDrop(&mut val).0 == 0), std::mem::take(&mut val)); + (assert!(*MutRefWithDrop(&mut val).0 == 0, "msg"), std::mem::take(&mut val)); } From 37d5a0343ce4f0044ebeef7b75ed47e58eea75e7 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Tue, 5 May 2026 23:53:24 -0700 Subject: [PATCH 002/116] Add VS Code new project command Implement a rust-analyzer VS Code command for creating new Cargo projects from the editor. Add command registration, UI entry points, configuration for post-create behavior, focused validation, and tests for the command flow. AI tools were used to research comparable editor behaviors and help refine the implementation plan; the resulting changes were reviewed before submission. --- .../rust-analyzer/editors/code/package.json | 40 +++ .../editors/code/src/commands.ts | 1 + .../rust-analyzer/editors/code/src/config.ts | 4 + .../rust-analyzer/editors/code/src/main.ts | 6 + .../editors/code/src/new_project.ts | 311 ++++++++++++++++++ .../editors/code/src/toolchain.ts | 45 ++- .../editors/code/tests/unit/commands.test.ts | 80 +++++ .../code/walkthrough-create-project.md | 9 + 8 files changed, 492 insertions(+), 4 deletions(-) create mode 100644 src/tools/rust-analyzer/editors/code/src/new_project.ts create mode 100644 src/tools/rust-analyzer/editors/code/tests/unit/commands.test.ts create mode 100644 src/tools/rust-analyzer/editors/code/walkthrough-create-project.md diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 14369e6f33e43..319b888e37b39 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -214,6 +214,11 @@ "title": "Reload workspace", "category": "rust-analyzer" }, + { + "command": "rust-analyzer.newProject", + "title": "Create New Project...", + "category": "rust-analyzer" + }, { "command": "rust-analyzer.rebuildProcMacros", "title": "Rebuild proc macros and build scripts", @@ -486,6 +491,23 @@ "markdownDescription": "Do not start rust-analyzer server when the extension is activated.", "default": false, "type": "boolean" + }, + "rust-analyzer.projectCreation.openAfterCreate": { + "markdownDescription": "Control what happens after `rust-analyzer: Create New Project...` finishes creating a Cargo project.", + "default": "ask", + "enum": [ + "ask", + "open", + "openNewWindow", + "addToWorkspace" + ], + "enumDescriptions": [ + "Prompt for how to open the new project.", + "Open the new project in the current window.", + "Open the new project in a new window.", + "Add the new project to the current workspace, or open it if no workspace is open." + ], + "type": "string" } } }, @@ -3804,6 +3826,9 @@ "command": "rust-analyzer.memoryUsage", "when": "inRustProject" }, + { + "command": "rust-analyzer.newProject" + }, { "command": "rust-analyzer.reloadWorkspace", "when": "inRustProject" @@ -3919,6 +3944,13 @@ } ] }, + "viewsWelcome": [ + { + "view": "explorer", + "contents": "Create a new Rust project.\n[Create Rust Project](command:rust-analyzer.newProject)", + "when": "workspaceFolderCount == 0" + } + ], "viewsContainers": { "activitybar": [ { @@ -3944,6 +3976,14 @@ "title": "Learn about rust-analyzer", "description": "A brief introduction to get started with rust-analyzer. Learn about key features and resources to help you get the most out of the extension.", "steps": [ + { + "id": "create-project", + "title": "Create a Rust project", + "description": "Start a new Cargo binary or library project from VS Code.\n\n[Create a Rust Project](command:rust-analyzer.newProject)", + "media": { + "markdown": "./walkthrough-create-project.md" + } + }, { "id": "setup", "title": "Useful Setup Tips", diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 302f51dee44d2..66c981428a4ea 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -33,6 +33,7 @@ import { log } from "./util"; import type { SyntaxElement } from "./syntax_tree_provider"; export * from "./run"; +export { newProject } from "./new_project"; export function analyzerStatus(ctx: CtxInit): Cmd { const tdcp = new (class implements vscode.TextDocumentContentProvider { diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index d65f011c754be..0f783c71b9541 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -447,6 +447,10 @@ export class Config { return this.get("initializeStopped"); } + get projectCreationOpenAfterCreate() { + return this.get("projectCreation.openAfterCreate"); + } + get askBeforeUpdateTest() { return this.get("runnables.askBeforeUpdateTest"); } diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 7d91286552aaa..d32d49b485e72 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -161,6 +161,12 @@ function createCommands(): Record { memoryUsage: { enabled: commands.memoryUsage }, reloadWorkspace: { enabled: commands.reloadWorkspace }, rebuildProcMacros: { enabled: commands.rebuildProcMacros }, + newProject: { + // Project creation is a pure VS Code-side workflow and should stay available even in + // empty windows before rust-analyzer has started or a Rust workspace exists. + enabled: commands.newProject, + disabled: commands.newProject, + }, matchingBrace: { enabled: commands.matchingBrace }, joinLines: { enabled: commands.joinLines }, parentModule: { enabled: commands.parentModule }, diff --git a/src/tools/rust-analyzer/editors/code/src/new_project.ts b/src/tools/rust-analyzer/editors/code/src/new_project.ts new file mode 100644 index 0000000000000..da3181ea3ec98 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/new_project.ts @@ -0,0 +1,311 @@ +import * as vscode from "vscode"; + +import type { Ctx, Cmd } from "./ctx"; +import * as ra from "./lsp_ext"; +import { cargoPath } from "./toolchain"; +import { log, spawnAsync } from "./util"; + +type NewProjectKind = "bin" | "lib"; +type NewProjectOpenAction = "open" | "openNewWindow" | "addToWorkspace"; + +type NewProjectTemplate = { + detail: string; + id: NewProjectKind; + label: string; +}; + +type NewProjectCargo = { + cargo: string; + cargoEnv: NodeJS.ProcessEnv; +}; + +const NEW_PROJECT_TEMPLATES: readonly NewProjectTemplate[] = [ + { + id: "bin", + label: "Binary Application", + detail: "Create a Cargo binary package (`cargo new --bin`)", + }, + { + id: "lib", + label: "Library", + detail: "Create a Cargo library package (`cargo new --lib`)", + }, +] as const; + +export function newProject(ctx: Ctx): Cmd { + return async () => { + const cargo = await resolveNewProjectCargo(ctx); + + const selectedKind = await promptForNewProjectTemplate(); + if (!selectedKind) { + return; + } + + const parentFolder = await promptForNewProjectParentFolder(); + if (!parentFolder) { + return; + } + + const projectName = await promptForNewProjectName(parentFolder); + if (!projectName) { + return; + } + + if (!(await createNewProject(cargo, parentFolder, selectedKind, projectName))) { + return; + } + + const projectUri = vscode.Uri.joinPath(parentFolder, projectName); + const defaultAction = determineNewProjectOpenAction( + ctx.config.projectCreationOpenAfterCreate, + Boolean(vscode.workspace.workspaceFolders?.length), + ); + const action = + defaultAction === "ask" + ? await promptForNewProjectOpenAction( + projectName, + Boolean(vscode.workspace.workspaceFolders?.length), + ) + : defaultAction; + + if (action) { + await executeNewProjectOpenAction(ctx, action, projectUri); + } + }; +} + +async function resolveNewProjectCargo(ctx: Ctx): Promise { + // Use the same effective environment rust-analyzer uses elsewhere so project creation sees + // toolchain wrappers, PATH overrides, and CARGO_HOME changes from configuration. + const cargoEnv = { ...process.env, ...ctx.config.serverExtraEnv }; + return { cargo: await cargoPath(cargoEnv), cargoEnv }; +} + +async function promptForNewProjectTemplate(): Promise { + const selected = await vscode.window.showQuickPick(NEW_PROJECT_TEMPLATES, { + placeHolder: "Select a Rust project kind", + }); + return selected?.id; +} + +async function promptForNewProjectParentFolder(): Promise { + const selectedFolder = await vscode.window.showOpenDialog({ + title: "Select the parent folder for the new Rust project", + openLabel: "Select parent folder", + canSelectFiles: false, + canSelectFolders: true, + canSelectMany: false, + }); + if (!selectedFolder?.length) { + return undefined; + } + return selectedFolder[0]; +} + +const CARGO_MANIFEST_NAME_PATTERN = /^[\p{Alphabetic}\p{Number}_-]+$/u; + +// Keep local validation focused on stable checks that can be reported in the input box, then let +// `cargo new` remain the source of truth for package-name-specific identifier and keyword rules. +export function validateNewProjectName( + value: string, + existingNames: readonly string[], +): string | undefined { + const trimmedValue = value.trim(); + if (trimmedValue.length === 0) { + return "Project name cannot be empty."; + } + if (trimmedValue.includes("/") || trimmedValue.includes("\\")) { + return "Project name cannot contain '/' or '\\' characters."; + } + if (trimmedValue === "." || trimmedValue === "..") { + return "Project name cannot be '.' or '..'."; + } + if (!CARGO_MANIFEST_NAME_PATTERN.test(trimmedValue)) { + return "Project name can contain only alphanumeric characters, '-' or '_'."; + } + if (existingNames.includes(trimmedValue)) { + return "A file or folder with this name already exists."; + } + return undefined; +} + +async function promptForNewProjectName(parentFolder: vscode.Uri): Promise { + let existingNames: string[] = []; + try { + const entries = await vscode.workspace.fs.readDirectory(parentFolder); + existingNames = entries.map(([name]) => name); + } catch (error) { + log.error("Failed to read project parent folder", error); + void vscode.window.showErrorMessage("Failed to read the selected parent folder."); + return undefined; + } + + const projectName = await vscode.window.showInputBox({ + prompt: `Enter the new project name to create inside ${parentFolder.fsPath}`, + validateInput: async (value) => validateNewProjectName(value, existingNames), + }); + return projectName?.trim(); +} + +export function cargoNewArgs(kind: NewProjectKind, name: string): string[] { + return ["new", kind === "bin" ? "--bin" : "--lib", name]; +} + +async function createNewProject( + cargo: NewProjectCargo, + parentFolder: vscode.Uri, + kind: NewProjectKind, + projectName: string, +): Promise { + const args = cargoNewArgs(kind, projectName); + const createResult = await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: `Creating Rust project ${projectName}`, + }, + async () => + spawnAsync(cargo.cargo, args, { + cwd: parentFolder.fsPath, + env: cargo.cargoEnv, + }), + ); + + if (createResult.error || createResult.status !== 0) { + const details = formatProcessDetails(createResult); + await showNewProjectError("Failed to create Rust project.", details || undefined, { + cargo: cargo.cargo, + args, + cwd: parentFolder.fsPath, + error: createResult.error?.message, + status: createResult.status, + stderr: createResult.stderr || undefined, + stdout: createResult.stdout || undefined, + }); + return false; + } + + return true; +} + +function formatProcessDetails(result: { error?: Error; stderr: string; stdout: string }): string { + return [result.stderr, result.stdout, result.error?.message] + .filter((value): value is string => Boolean(value && value.trim().length > 0)) + .join("\n") + .trim(); +} + +async function showNewProjectError( + message: string, + details: string | undefined, + logContext: { + cargo: string; + args: string[]; + cwd?: string; + error?: string; + status: number | null; + stderr?: string; + stdout?: string; + }, +): Promise { + // Keep command-failure logging focused on the invocation and process output. Environment + // variables may contain secrets such as API keys, tokens, and credentials, so failure logs + // must not dump the merged env here. + const commandLine = [logContext.cargo, ...logContext.args].join(" "); + log.error(message); + log.error(`command: ${commandLine}`); + if (logContext.cwd) { + log.error(`cwd: ${logContext.cwd}`); + } + log.error(`exit status: ${String(logContext.status)}`); + if (logContext.error) { + log.error(`error: ${logContext.error}`); + } + if (logContext.stderr) { + log.error(`stderr:\n${logContext.stderr}`); + } + if (logContext.stdout) { + log.error(`stdout:\n${logContext.stdout}`); + } + const selection = await vscode.window.showErrorMessage( + details ? `${message}\n${details}` : message, + "Open Logs", + ); + if (selection === "Open Logs") { + await vscode.commands.executeCommand("rust-analyzer.openLogs"); + } +} + +export function determineNewProjectOpenAction( + configuredAction: string | undefined, + hasWorkspaceFolders: boolean, +): "ask" | NewProjectOpenAction { + switch (configuredAction) { + case "open": + case "openNewWindow": + return configuredAction; + case "addToWorkspace": + // Adding to a workspace only makes sense when one is already open. Falling back to + // "open" keeps the setting usable in empty windows without adding another prompt path. + return hasWorkspaceFolders ? configuredAction : "open"; + default: + return "ask"; + } +} + +async function promptForNewProjectOpenAction( + projectName: string, + hasWorkspaceFolders: boolean, +): Promise { + let message = `Would you like to open ${projectName}?`; + const open = "Open"; + const openNewWindow = "Open in New Window"; + const choices = [open, openNewWindow]; + + const addToWorkspace = "Add to VS Code Workspace"; + if (hasWorkspaceFolders) { + message = `Would you like to open ${projectName}, or add it to the current VS Code workspace?`; + choices.push(addToWorkspace); + } + + const result = await vscode.window.showInformationMessage( + message, + { modal: true, detail: "The default action can be configured in settings." }, + ...choices, + ); + + const actionMap: Record = { + [open]: "open", + [openNewWindow]: "openNewWindow", + [addToWorkspace]: "addToWorkspace", + }; + return result ? actionMap[result] : undefined; +} + +async function executeNewProjectOpenAction( + ctx: Ctx, + action: NewProjectOpenAction, + projectUri: vscode.Uri, +): Promise { + if (action === "open") { + await vscode.commands.executeCommand("vscode.openFolder", projectUri, { + forceReuseWindow: true, + }); + return; + } + + if (action === "openNewWindow") { + await vscode.commands.executeCommand("vscode.openFolder", projectUri, { + forceNewWindow: true, + }); + return; + } + + const index = vscode.workspace.workspaceFolders?.length ?? 0; + vscode.workspace.updateWorkspaceFolders(index, 0, { uri: projectUri }); + // Reuse the existing workspace window when requested, but nudge rust-analyzer afterwards so + // the newly added Cargo project is discovered immediately instead of waiting for a later + // background refresh. + if (ctx.client?.isRunning()) { + await ctx.client.sendRequest(ra.reloadWorkspace); + } +} diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts index 76946d1510162..784ee260d088e 100644 --- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts +++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts @@ -160,9 +160,44 @@ export function cargoPath(env?: Env): Promise { if (env?.["RUSTC_TOOLCHAIN"]) { return Promise.resolve("cargo"); } + if (env) { + return getPathForExecutableWithEnv("cargo", env); + } return getPathForExecutable("cargo"); } +/** + * Resolves an executable using an explicitly supplied environment instead of the VS Code host + * process environment. + * + * Some extension call sites already construct the exact env they will use for spawning, so path + * resolution needs to honor that same `PATH`/`CARGO_HOME` view to avoid launching a different + * toolchain than the one that was resolved. + */ +async function getPathForExecutableWithEnv( + executableName: "cargo" | "rustc" | "rustup", + env: Env, +): Promise { + const envVar = env[executableName.toUpperCase()]; + if (envVar) { + return envVar; + } + + if (await lookupInPath(executableName, env["PATH"] ?? "")) { + return executableName; + } + + const cargoHome = getCargoHomeFromPath(env["CARGO_HOME"]); + if (cargoHome) { + const standardPath = vscode.Uri.joinPath(cargoHome, "bin", executableName); + if (await isFileAtUri(standardPath)) { + return standardPath.fsPath; + } + } + + return executableName; +} + /** Mirrors `toolchain::get_path_for_executable()` implementation */ const getPathForExecutable = memoizeAsync( // We apply caching to decrease file-system interactions @@ -172,7 +207,7 @@ const getPathForExecutable = memoizeAsync( if (envVar) return envVar; } - if (await lookupInPath(executableName)) return executableName; + if (await lookupInPath(executableName, process.env["PATH"] ?? "")) return executableName; const cargoHome = getCargoHome(); if (cargoHome) { @@ -183,9 +218,7 @@ const getPathForExecutable = memoizeAsync( }, ); -async function lookupInPath(exec: string): Promise { - const paths = process.env["PATH"] ?? ""; - +async function lookupInPath(exec: string, paths: string): Promise { const candidates = paths.split(path.delimiter).flatMap((dirInPath) => { const candidate = path.join(dirInPath, exec); return os.type() === "Windows_NT" ? [candidate, `${candidate}.exe`] : [candidate]; @@ -201,6 +234,10 @@ async function lookupInPath(exec: string): Promise { function getCargoHome(): vscode.Uri | null { const envVar = process.env["CARGO_HOME"]; + return getCargoHomeFromPath(envVar); +} + +function getCargoHomeFromPath(envVar: string | undefined): vscode.Uri | null { if (envVar) return vscode.Uri.file(envVar); try { diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/commands.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/commands.test.ts new file mode 100644 index 0000000000000..900bb2779d565 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tests/unit/commands.test.ts @@ -0,0 +1,80 @@ +import * as assert from "node:assert/strict"; + +import { + cargoNewArgs, + determineNewProjectOpenAction, + validateNewProjectName, +} from "../../src/new_project"; +import type { Context } from "."; + +export async function getTests(ctx: Context) { + await ctx.suite("New project command", (suite) => { + suite.addTest("rejects empty project name", async () => { + assert.equal(validateNewProjectName("", []), "Project name cannot be empty."); + assert.equal(validateNewProjectName(" ", []), "Project name cannot be empty."); + }); + + suite.addTest("rejects dot project names", async () => { + assert.equal(validateNewProjectName(".", []), "Project name cannot be '.' or '..'."); + assert.equal(validateNewProjectName("..", []), "Project name cannot be '.' or '..'."); + }); + + suite.addTest("rejects path separators", async () => { + assert.equal( + validateNewProjectName("foo/bar", []), + "Project name cannot contain '/' or '\\' characters.", + ); + assert.equal( + validateNewProjectName("foo\\bar", []), + "Project name cannot contain '/' or '\\' characters.", + ); + }); + + suite.addTest("rejects invalid Cargo package name characters", async () => { + assert.equal( + validateNewProjectName("foo.bar", []), + "Project name can contain only alphanumeric characters, '-' or '_'.", + ); + assert.equal( + validateNewProjectName("foo bar", []), + "Project name can contain only alphanumeric characters, '-' or '_'.", + ); + assert.equal( + validateNewProjectName("foo+bar", []), + "Project name can contain only alphanumeric characters, '-' or '_'.", + ); + }); + + suite.addTest("rejects existing child folder collisions", async () => { + assert.equal( + validateNewProjectName("demo", ["demo"]), + "A file or folder with this name already exists.", + ); + }); + + suite.addTest("accepts a normal project name", async () => { + assert.equal(validateNewProjectName("demo-project", []), undefined); + }); + + suite.addTest("resolves addToWorkspace fallback without workspace", async () => { + assert.equal(determineNewProjectOpenAction("addToWorkspace", false), "open"); + }); + + suite.addTest("keeps addToWorkspace when workspace exists", async () => { + assert.equal(determineNewProjectOpenAction("addToWorkspace", true), "addToWorkspace"); + }); + + suite.addTest("defaults to ask for unknown values", async () => { + assert.equal(determineNewProjectOpenAction(undefined, true), "ask"); + assert.equal(determineNewProjectOpenAction("ask", true), "ask"); + }); + + suite.addTest("builds binary cargo args", async () => { + assert.deepEqual(cargoNewArgs("bin", "demo"), ["new", "--bin", "demo"]); + }); + + suite.addTest("builds library cargo args", async () => { + assert.deepEqual(cargoNewArgs("lib", "demo"), ["new", "--lib", "demo"]); + }); + }); +} diff --git a/src/tools/rust-analyzer/editors/code/walkthrough-create-project.md b/src/tools/rust-analyzer/editors/code/walkthrough-create-project.md new file mode 100644 index 0000000000000..34c04cdd1db4a --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/walkthrough-create-project.md @@ -0,0 +1,9 @@ +# Create a New Cargo Project + +Create a new Cargo project without leaving VS Code. + +The command lets you choose the package kind, parent folder, project name, and +how the new project should be opened afterward. + +The project is created with Cargo, so the generated files and defaults match +the normal `cargo new` experience. From d061dcb71f45ade7f38578edbbcbe486349037e8 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sun, 24 May 2026 14:20:29 -0300 Subject: [PATCH 003/116] Fix misattributed type inference error span for index expressions When an index expression with an ambiguous type (e.g. `arr[idx.into()]`) appears inside a cast or binary operation, the type inference error was incorrectly attributed to the outer expression instead of the `.into()` call. Resolve the index sub-expression type first so the error points at the actual ambiguous site. --- compiler/rustc_hir_typeck/src/cast.rs | 16 ++++++- compiler/rustc_hir_typeck/src/op.rs | 10 +++++ .../index-expr-ambiguous-type.rs | 30 +++++++++++++ .../index-expr-ambiguous-type.stderr | 42 +++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/ui/type-inference/index-expr-ambiguous-type.rs create mode 100644 tests/ui/type-inference/index-expr-ambiguous-type.stderr diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 4d934703f4670..97ff7765896a8 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -727,7 +727,21 @@ impl<'a, 'tcx> CastCheck<'tcx> { #[instrument(skip(fcx), level = "debug")] pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { - self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty); + if let hir::ExprKind::Index(_, idx, _) = self.expr.kind + && self.expr_ty.has_infer() + { + let idx_ty = fcx.resolve_vars_if_possible(fcx.node_ty(idx.hir_id)); + if idx_ty.is_ty_var() { + let resolved = fcx.structurally_resolve_type(idx.span, idx_ty); + if resolved.references_error() { + self.expr_ty = resolved; + } + } + } + // Skip if idx resolution above already emitted a diagnostic and set expr_ty to error. + if !self.expr_ty.references_error() { + self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty); + } self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 1e9986fa761c4..0a67b384ae8de 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -313,6 +313,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); + + if method.sig.output().has_infer() + && let hir::ExprKind::Index(_, idx, _) = rhs_expr.kind + { + let idx_ty = self.resolve_vars_if_possible(self.node_ty(idx.hir_id)); + if idx_ty.is_ty_var() { + self.structurally_resolve_type(idx.span, idx_ty); + } + } + method.sig.output() } // error types are considered "builtin" diff --git a/tests/ui/type-inference/index-expr-ambiguous-type.rs b/tests/ui/type-inference/index-expr-ambiguous-type.rs new file mode 100644 index 0000000000000..32b45703e2003 --- /dev/null +++ b/tests/ui/type-inference/index-expr-ambiguous-type.rs @@ -0,0 +1,30 @@ +// Regression test for #156738 +// +// When the index type in `arr[idx]` is ambiguous, the error should point +// at the index sub-expression, not the whole indexing expression or +// surrounding operators. + +fn with_cast() { + let bad_idx = 0u8; + let _foo = [1, 2, 3][bad_idx.into()] as i32; + //~^ ERROR type annotations needed +} + +fn with_binop() { + let bad_idx = 0u8; + let _foo = 0 + [1, 2, 3][bad_idx.into()]; + //~^ ERROR type annotations needed +} + +fn standalone() { + let bad_idx = 0u8; + let _foo = [1, 2, 3][bad_idx.into()]; + //~^ ERROR type annotations needed +} + +fn with_known_index_type() { + let bad_idx = 0u8; + let _foo = [1, 2, 3][Into::::into(bad_idx)] as i32; +} + +fn main() {} diff --git a/tests/ui/type-inference/index-expr-ambiguous-type.stderr b/tests/ui/type-inference/index-expr-ambiguous-type.stderr new file mode 100644 index 0000000000000..80c0aa6c4a952 --- /dev/null +++ b/tests/ui/type-inference/index-expr-ambiguous-type.stderr @@ -0,0 +1,42 @@ +error[E0282]: type annotations needed + --> $DIR/index-expr-ambiguous-type.rs:9:34 + | +LL | let _foo = [1, 2, 3][bad_idx.into()] as i32; + | ^^^^ + | +help: try using a fully qualified path to specify the expected types + | +LL - let _foo = [1, 2, 3][bad_idx.into()] as i32; +LL + let _foo = [1, 2, 3][>::into(bad_idx)] as i32; + | + +error[E0282]: type annotations needed + --> $DIR/index-expr-ambiguous-type.rs:15:38 + | +LL | let _foo = 0 + [1, 2, 3][bad_idx.into()]; + | ^^^^ + | +help: try using a fully qualified path to specify the expected types + | +LL - let _foo = 0 + [1, 2, 3][bad_idx.into()]; +LL + let _foo = 0 + [1, 2, 3][>::into(bad_idx)]; + | + +error[E0283]: type annotations needed + --> $DIR/index-expr-ambiguous-type.rs:21:34 + | +LL | let _foo = [1, 2, 3][bad_idx.into()]; + | ^^^^ + | + = note: the type must implement `From` + = note: required for `u8` to implement `Into<_>` +help: try using a fully qualified path to specify the expected types + | +LL - let _foo = [1, 2, 3][bad_idx.into()]; +LL + let _foo = [1, 2, 3][>::into(bad_idx)]; + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`. From f018c4eb6413b8e578406a0c1c2b0d0cd02572d6 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sun, 24 May 2026 17:50:15 -0700 Subject: [PATCH 004/116] Fix new-project log handling Point the new project failure flow at the extension logs and make the log-opening command available when the language server is not running. Also add tests for the env-aware cargo path resolution path introduced for project creation. --- .../editors/code/src/new_project.ts | 6 +-- .../rust-analyzer/editors/code/src/util.ts | 6 ++- .../code/tests/unit/launch_config.test.ts | 44 ++++++++++++++++++- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/src/new_project.ts b/src/tools/rust-analyzer/editors/code/src/new_project.ts index da3181ea3ec98..f5f6d86da04df 100644 --- a/src/tools/rust-analyzer/editors/code/src/new_project.ts +++ b/src/tools/rust-analyzer/editors/code/src/new_project.ts @@ -228,10 +228,10 @@ async function showNewProjectError( } const selection = await vscode.window.showErrorMessage( details ? `${message}\n${details}` : message, - "Open Logs", + "Open Extension Logs", ); - if (selection === "Open Logs") { - await vscode.commands.executeCommand("rust-analyzer.openLogs"); + if (selection === "Open Extension Logs") { + log.show(); } } diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts index 05b475080cbd2..ddeec814b4158 100644 --- a/src/tools/rust-analyzer/editors/code/src/util.ts +++ b/src/tools/rust-analyzer/editors/code/src/util.ts @@ -22,6 +22,10 @@ class Log { log: true, }); + show(): void { + this.output.show(true); + } + trace(...messages: [unknown, ...unknown[]]): void { this.output.trace(this.stringify(messages)); } @@ -40,7 +44,7 @@ class Log { error(...messages: [unknown, ...unknown[]]): void { this.output.error(this.stringify(messages)); - this.output.show(true); + this.show(); } private stringify(messages: unknown[]): string { diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts index eeb8608a42db5..69be84dcea6df 100644 --- a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts +++ b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts @@ -1,5 +1,8 @@ import * as assert from "assert"; -import { Cargo } from "../../src/toolchain"; +import * as os from "os"; +import * as path from "path"; +import { mkdtemp, mkdir, rm, writeFile } from "fs/promises"; +import { Cargo, cargoPath } from "../../src/toolchain"; import type { Context } from "."; export async function getTests(ctx: Context) { @@ -96,4 +99,43 @@ export async function getTests(ctx: Context) { assert.notDeepStrictEqual(args.filter, undefined); }); }); + + await ctx.suite("Toolchain resolution", (suite) => { + suite.addTest("prefers explicit CARGO from provided env", async () => { + const explicitCargo = path.join(os.tmpdir(), "custom-cargo"); + assert.strictEqual(await cargoPath({ CARGO: explicitCargo }), explicitCargo); + }); + + suite.addTest("resolves cargo from provided PATH", async () => { + const tempDir = await mkdtemp(path.join(os.tmpdir(), "ra-cargo-path-")); + try { + const cargoBinary = path.join(tempDir, process.platform === "win32" ? "cargo.exe" : "cargo"); + await writeFile(cargoBinary, ""); + + assert.strictEqual(await cargoPath({ PATH: tempDir }), "cargo"); + } finally { + await rm(tempDir, { recursive: true, force: true }); + } + }); + + suite.addTest("resolves cargo from provided CARGO_HOME", async () => { + const cargoHome = await mkdtemp(path.join(os.tmpdir(), "ra-cargo-home-")); + try { + const binDir = path.join(cargoHome, "bin"); + await mkdir(binDir); + const cargoBinary = path.join( + binDir, + process.platform === "win32" ? "cargo.exe" : "cargo", + ); + await writeFile(cargoBinary, ""); + + assert.strictEqual( + await cargoPath({ PATH: "", CARGO_HOME: cargoHome }), + cargoBinary, + ); + } finally { + await rm(cargoHome, { recursive: true, force: true }); + } + }); + }); } From abba25eb718b26dbef19c2ed6716abfe093d47b6 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 25 May 2026 16:06:14 +0800 Subject: [PATCH 005/116] fix: rename schema subItems with sub_items --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 4 ++-- .../rust-analyzer/docs/book/src/configuration_generated.md | 2 +- src/tools/rust-analyzer/editors/code/package.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 6f532e4224885..74ba183f97ddb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -662,7 +662,7 @@ config_data! { /// For traits the type "methods" can be used to only exclude the methods but not the trait /// itself. /// - /// For modules the type "subItems" can be used to only exclude the all items in it but not the module + /// For modules the type "sub_items" can be used to only exclude the all items in it but not the module /// itself. This does not include items defined in nested modules. /// /// This setting also inherits `#rust-analyzer.completion.excludeTraits#`. @@ -4135,7 +4135,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json }, "type": { "type": "string", - "enum": ["always", "methods", "subItems"], + "enum": ["always", "methods", "sub_items"], "enumDescriptions": [ "Do not show this item or its methods (if it is a trait) in auto-import completions.", "Do not show this trait's methods in auto-import completions.", diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 7bbb9e0258169..bc5ef9e96c02a 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -446,7 +446,7 @@ verbose form `{ "path": "path::to::item", type: "always" }`. For traits the type "methods" can be used to only exclude the methods but not the trait itself. -For modules the type "subItems" can be used to only exclude the all items in it but not the module +For modules the type "sub_items" can be used to only exclude the all items in it but not the module itself. This does not include items defined in nested modules. This setting also inherits `#rust-analyzer.completion.excludeTraits#`. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 8df606d4c4ca8..9ca1e80c6ac7b 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1328,7 +1328,7 @@ "title": "Completion", "properties": { "rust-analyzer.completion.autoimport.exclude": { - "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more\nverbose form `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait\nitself.\n\nFor modules the type \"subItems\" can be used to only exclude the all items in it but not the module\nitself. This does not include items defined in nested modules.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", + "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more\nverbose form `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait\nitself.\n\nFor modules the type \"sub_items\" can be used to only exclude the all items in it but not the module\nitself. This does not include items defined in nested modules.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", "default": [ { "path": "core::borrow::Borrow", @@ -1356,7 +1356,7 @@ "enum": [ "always", "methods", - "subItems" + "sub_items" ], "enumDescriptions": [ "Do not show this item or its methods (if it is a trait) in auto-import completions.", From 460c582f863e57825436d4541a2620c8b56f5566 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Mon, 25 May 2026 14:05:59 -0700 Subject: [PATCH 006/116] Format launch config test Run the VS Code formatter to fix the remaining Prettier issue in the launch config test before updating rust-lang/rust-analyzer#22103. AI-assisted: OpenAI Codex was used to identify and apply this change. --- .../editors/code/tests/unit/launch_config.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts index 69be84dcea6df..9bba33f8e9d20 100644 --- a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts +++ b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts @@ -109,7 +109,10 @@ export async function getTests(ctx: Context) { suite.addTest("resolves cargo from provided PATH", async () => { const tempDir = await mkdtemp(path.join(os.tmpdir(), "ra-cargo-path-")); try { - const cargoBinary = path.join(tempDir, process.platform === "win32" ? "cargo.exe" : "cargo"); + const cargoBinary = path.join( + tempDir, + process.platform === "win32" ? "cargo.exe" : "cargo", + ); await writeFile(cargoBinary, ""); assert.strictEqual(await cargoPath({ PATH: tempDir }), "cargo"); From b8155a639ddfafaf00a15ba1c3e5cab3e544354b Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Mon, 25 May 2026 14:05:59 -0700 Subject: [PATCH 007/116] Fix VS Code cargo executable probing Handle Windows executable suffixes when the VS Code extension probes for cargo through PATH or CARGO_HOME, and preserve case-insensitive environment variable lookup for supplied env objects so copied Windows `Path` entries still resolve cargo. Normalize and document the Windows CARGO_HOME test comparison as well, because VS Code path resolution can lowercase the drive letter in `fsPath` without changing which executable was found. This keeps the extension-side lookup aligned with the Rust-side toolchain helper behavior and avoids breaking create-project on common Windows setups. AI-assisted: OpenAI Codex was used to identify and apply this change. --- .../editors/code/src/toolchain.ts | 41 ++++++++++++++----- .../code/tests/unit/launch_config.test.ts | 24 ++++++----- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts index 784ee260d088e..6ae365c71c7ac 100644 --- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts +++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts @@ -3,7 +3,7 @@ import * as os from "os"; import * as path from "path"; import * as readline from "readline"; import * as vscode from "vscode"; -import { Env, log, memoizeAsync, unwrapUndefinable } from "./util"; +import { Env, isWindows, log, memoizeAsync, unwrapUndefinable } from "./util"; import type { CargoRunnableArgs } from "./lsp_ext"; interface CompilationArtifact { @@ -178,20 +178,22 @@ async function getPathForExecutableWithEnv( executableName: "cargo" | "rustc" | "rustup", env: Env, ): Promise { - const envVar = env[executableName.toUpperCase()]; + const envVar = getEnvVar(env, executableName.toUpperCase()); if (envVar) { return envVar; } - if (await lookupInPath(executableName, env["PATH"] ?? "")) { + if (await lookupInPath(executableName, getEnvVar(env, "PATH") ?? "")) { return executableName; } - const cargoHome = getCargoHomeFromPath(env["CARGO_HOME"]); + const cargoHome = getCargoHomeFromPath(getEnvVar(env, "CARGO_HOME")); if (cargoHome) { - const standardPath = vscode.Uri.joinPath(cargoHome, "bin", executableName); - if (await isFileAtUri(standardPath)) { - return standardPath.fsPath; + for (const candidate of executableCandidates(executableName)) { + const standardPath = vscode.Uri.joinPath(cargoHome, "bin", candidate); + if (await isFileAtUri(standardPath)) { + return standardPath.fsPath; + } } } @@ -211,8 +213,10 @@ const getPathForExecutable = memoizeAsync( const cargoHome = getCargoHome(); if (cargoHome) { - const standardPath = vscode.Uri.joinPath(cargoHome, "bin", executableName); - if (await isFileAtUri(standardPath)) return standardPath.fsPath; + for (const candidate of executableCandidates(executableName)) { + const standardPath = vscode.Uri.joinPath(cargoHome, "bin", candidate); + if (await isFileAtUri(standardPath)) return standardPath.fsPath; + } } return executableName; }, @@ -220,8 +224,7 @@ const getPathForExecutable = memoizeAsync( async function lookupInPath(exec: string, paths: string): Promise { const candidates = paths.split(path.delimiter).flatMap((dirInPath) => { - const candidate = path.join(dirInPath, exec); - return os.type() === "Windows_NT" ? [candidate, `${candidate}.exe`] : [candidate]; + return executableCandidates(exec).map((candidate) => path.join(dirInPath, candidate)); }); for await (const isFile of candidates.map(isFileAtPath)) { @@ -232,6 +235,22 @@ async function lookupInPath(exec: string, paths: string): Promise { return false; } +function executableCandidates(executableName: string): string[] { + // Keep the extension-side probe aligned with `crates/toolchain::probe_for_binary()`, which + // checks both the bare executable name and the platform suffix such as `.exe` on Windows. + // That matters for both PATH lookups and `$CARGO_HOME/bin/` fallbacks. + return isWindows ? [executableName, `${executableName}.exe`] : [executableName]; +} + +function getEnvVar(env: Env, name: string): string | undefined { + if (!isWindows) { + return env[name]; + } + + const foldedName = name.toLowerCase(); + return Object.entries(env).find(([key]) => key.toLowerCase() === foldedName)?.[1]; +} + function getCargoHome(): vscode.Uri | null { const envVar = process.env["CARGO_HOME"]; return getCargoHomeFromPath(envVar); diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts index 9bba33f8e9d20..8da62cd241655 100644 --- a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts +++ b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts @@ -3,6 +3,7 @@ import * as os from "os"; import * as path from "path"; import { mkdtemp, mkdir, rm, writeFile } from "fs/promises"; import { Cargo, cargoPath } from "../../src/toolchain"; +import { isWindows, normalizeDriveLetter } from "../../src/util"; import type { Context } from "."; export async function getTests(ctx: Context) { @@ -109,13 +110,11 @@ export async function getTests(ctx: Context) { suite.addTest("resolves cargo from provided PATH", async () => { const tempDir = await mkdtemp(path.join(os.tmpdir(), "ra-cargo-path-")); try { - const cargoBinary = path.join( - tempDir, - process.platform === "win32" ? "cargo.exe" : "cargo", - ); + const cargoBinary = path.join(tempDir, isWindows ? "cargo.exe" : "cargo"); await writeFile(cargoBinary, ""); - assert.strictEqual(await cargoPath({ PATH: tempDir }), "cargo"); + const pathKey = isWindows ? "Path" : "PATH"; + assert.strictEqual(await cargoPath({ [pathKey]: tempDir }), "cargo"); } finally { await rm(tempDir, { recursive: true, force: true }); } @@ -126,15 +125,12 @@ export async function getTests(ctx: Context) { try { const binDir = path.join(cargoHome, "bin"); await mkdir(binDir); - const cargoBinary = path.join( - binDir, - process.platform === "win32" ? "cargo.exe" : "cargo", - ); + const cargoBinary = path.join(binDir, isWindows ? "cargo.exe" : "cargo"); await writeFile(cargoBinary, ""); assert.strictEqual( - await cargoPath({ PATH: "", CARGO_HOME: cargoHome }), - cargoBinary, + normalizeComparablePath(await cargoPath({ PATH: "", CARGO_HOME: cargoHome })), + normalizeComparablePath(cargoBinary), ); } finally { await rm(cargoHome, { recursive: true, force: true }); @@ -142,3 +138,9 @@ export async function getTests(ctx: Context) { }); }); } + +function normalizeComparablePath(filePath: string): string { + // Windows path comparisons should ignore drive-letter casing because `fsPath` + // may normalize it differently while still pointing to the same file. + return normalizeDriveLetter(filePath, isWindows); +} From 1d9b66032c690ab3c47bec1f5341a62ef35b7d2e Mon Sep 17 00:00:00 2001 From: itang06 Date: Wed, 13 May 2026 00:59:07 -0700 Subject: [PATCH 008/116] internal: add item_list and mod_ constructors to SyntaxFactory Part of #18285 --- .../src/handlers/extract_module.rs | 5 +-- .../src/ast/syntax_factory/constructors.rs | 33 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index 40eaed0080a0a..4e30b3efb280e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -17,9 +17,10 @@ use syntax::{ ast::{ self, HasVisibility, edit::{AstNodeEdit, IndentLevel}, - make, + syntax_factory::SyntaxFactory, }, - match_ast, ted, + match_ast, + syntax_editor::{Position, SyntaxEditor}, }; use crate::{AssistContext, Assists}; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 2f7eab2423ce5..7f9cd1fce94eb 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -4,8 +4,8 @@ use either::Either; use crate::{ AstNode, Edition, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, ast::{ - self, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, - HasTypeBounds, HasVisibility, Lifetime, Param, RangeItem, make, + self, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasModuleItem, + HasName, HasTypeBounds, HasVisibility, Lifetime, Param, RangeItem, make, }, syntax_editor::SyntaxMappingBuilder, }; @@ -2015,6 +2015,35 @@ impl SyntaxFactory { make::assoc_item_list(None).clone_for_update() } + pub fn item_list(&self, items: impl IntoIterator) -> ast::ItemList { + let (items, input) = iterator_input(items); + let items_vec: Vec<_> = items.into_iter().collect(); + let ast = make::item_list(Some(items_vec)).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.items().map(|item: ast::Item| item.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + + pub fn mod_(&self, name: ast::Name, body: Option) -> ast::Module { + let ast = make::mod_(name.clone(), body.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + if let Some(body) = body { + builder.map_node(body.syntax().clone(), ast.item_list().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr { let ast = make::attr_outer(meta.clone()).clone_for_update(); From 37188cca9a41483f9dcd3e7d116dadb965aed672 Mon Sep 17 00:00:00 2001 From: itang06 Date: Wed, 13 May 2026 00:05:22 -0700 Subject: [PATCH 009/116] internal: migrate extract_module assist to SyntaxEditor --- .../src/handlers/extract_module.rs | 172 +++++++++++------- .../crates/syntax/src/ast/edit_in_place.rs | 10 - 2 files changed, 104 insertions(+), 78 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index 4e30b3efb280e..40c54e98820a8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -122,15 +122,18 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> let (usages_to_be_processed, record_fields, use_stmts_to_be_inserted) = module.get_usages_and_record_fields(ctx, module_text_range); + let make = SyntaxFactory::without_mappings(); + builder.edit_file(ctx.vfs_file_id()); use_stmts_to_be_inserted.into_iter().for_each(|(_, use_stmt)| { builder.insert(ctx.selection_trimmed().end(), format!("\n{use_stmt}")); }); - let import_items = module.resolve_imports(curr_parent_module, ctx); - module.change_visibility(record_fields); + let import_items = module.resolve_imports(curr_parent_module, ctx, &make); + module.change_visibility(record_fields, &make); - let module_def = generate_module_def(&impl_parent, &module).indent(old_item_indent); + let module_def = + generate_module_def(&impl_parent, &module, &make).indent(old_item_indent); let mut usages_to_be_processed_for_cur_file = vec![]; for (file_id, usages) in usages_to_be_processed { @@ -186,6 +189,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> fn generate_module_def( parent_impl: &Option, Module { name, body_items, use_items }: &Module, + make: &SyntaxFactory, ) -> ast::Module { let items: Vec<_> = if let Some(impl_) = parent_impl.as_ref() && let Some(self_ty) = impl_.self_ty() @@ -196,11 +200,15 @@ fn generate_module_def( .filter_map(ast::AssocItem::cast) .map(|it| it.indent(IndentLevel(1))) .collect_vec(); - let assoc_item_list = make::assoc_item_list(Some(assoc_items)).clone_for_update(); - let impl_ = impl_.reset_indent(); - ted::replace(impl_.get_or_create_assoc_item_list().syntax(), assoc_item_list.syntax()); + let impl_reset = impl_.reset_indent(); + let (editor, impl_root) = SyntaxEditor::with_ast_node(&impl_reset); + let assoc_item_list = editor.make().assoc_item_list(assoc_items); + if let Some(existing_list) = impl_root.assoc_item_list() { + editor.replace(existing_list.syntax(), assoc_item_list.syntax()); + } + let impl_ = ast::Impl::cast(editor.finish().new_root().clone()).unwrap(); // Add the import for enum/struct corresponding to given impl block - let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax()); + let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax(), make); once(use_impl) .chain(use_items.iter().cloned()) .chain(once(ast::Item::Impl(impl_))) @@ -210,19 +218,18 @@ fn generate_module_def( }; let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec(); - let module_body = make::item_list(Some(items)); - - let module_name = make::name(name); - make::mod_(module_name, Some(module_body)) + let module_body = make.item_list(items); + let module_name = make.name(name); + make.mod_(module_name, Some(module_body)) } -fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item { - let super_path = make::ext::ident_path("super"); - let node_path = make::ext::ident_path(&node_syntax.to_string()); - let use_ = make::use_( +fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode, make: &SyntaxFactory) -> ast::Item { + let super_path = make.ident_path("super"); + let node_path = make.path_from_text(&node_syntax.to_string()); + let use_ = make.use_( + [], None, - None, - make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false), + make.use_tree(make.path_concat(super_path, node_path), None, None, false), ); ast::Item::from(use_) @@ -386,18 +393,30 @@ impl Module { if use_.syntax().parent().is_some_and(|parent| parent == covering_node) && use_stmts_set.insert(use_.syntax().text_range().start()) { - let use_ = use_stmts_to_be_inserted - .entry(use_.syntax().text_range().start()) - .or_insert_with(|| use_.clone_subtree().clone_for_update()); - for seg in use_ - .syntax() - .descendants() - .filter_map(ast::NameRef::cast) - .filter(|seg| seg.syntax().to_string() == name_ref.to_string()) - { - let new_ref = make::path_from_text(&format!("{mod_name}::{seg}")) - .clone_for_update(); - ted::replace(seg.syntax().parent()?, new_ref.syntax()); + let key = use_.syntax().text_range().start(); + let entry = + use_stmts_to_be_inserted.entry(key).or_insert_with(|| use_.clone()); + let (editor, edit_root) = SyntaxEditor::with_ast_node(&*entry); + let replacements: Vec<_> = { + let make = editor.make(); + edit_root + .syntax() + .descendants() + .filter_map(ast::NameRef::cast) + .filter(|seg| seg.syntax().to_string() == name_ref.to_string()) + .filter_map(|seg| { + Some(( + seg.syntax().parent()?, + make.path_from_text(&format!("{mod_name}::{seg}")), + )) + }) + .collect() + }; + if !replacements.is_empty() { + for (parent, new_ref) in &replacements { + editor.replace(parent, new_ref.syntax()); + } + *entry = ast::Use::cast(editor.finish().new_root().clone()).unwrap(); } } } @@ -408,18 +427,23 @@ impl Module { } } - fn change_visibility(&mut self, record_fields: Vec) { + fn change_visibility(&mut self, record_fields: Vec, make: &SyntaxFactory) { + for item in &mut self.body_items { + let (_, root) = SyntaxEditor::with_ast_node(&item.reset_indent()); + *item = root; + } + let (mut replacements, record_field_parents, impls) = - get_replacements_for_visibility_change(&mut self.body_items, false); + get_replacements_for_visibility_change(&self.body_items); - let mut impl_items = impls + let impl_items = impls .into_iter() .flat_map(|impl_| impl_.syntax().descendants()) .filter_map(ast::Item::cast) .collect_vec(); let (mut impl_item_replacements, _, _) = - get_replacements_for_visibility_change(&mut impl_items, true); + get_replacements_for_visibility_change(&impl_items); replacements.append(&mut impl_item_replacements); @@ -433,17 +457,39 @@ impl Module { } } - for (vis, syntax) in replacements { - let item = syntax.children_with_tokens().find(|node_or_token| { - match node_or_token.kind() { - // We're skipping comments, doc comments, and attribute macros that may precede the keyword - // that the visibility should be placed before. - SyntaxKind::COMMENT | SyntaxKind::ATTR | SyntaxKind::WHITESPACE => false, - _ => true, - } - }); + for body_item in &mut self.body_items { + let insert_targets: Vec<_> = replacements + .iter() + .filter(|(vis, syntax)| { + vis.is_none() + && (syntax == body_item.syntax() + || syntax.ancestors().any(|a| &a == body_item.syntax())) + }) + .filter_map(|(_, syntax)| { + syntax.children_with_tokens().find(|nt| { + !matches!( + nt.kind(), + SyntaxKind::COMMENT | SyntaxKind::ATTR | SyntaxKind::WHITESPACE + ) + }) + }) + .collect(); - add_change_vis(vis, item); + if insert_targets.is_empty() { + continue; + } + + let (editor, _) = SyntaxEditor::new(body_item.syntax().clone()); + for target in insert_targets { + editor.insert_all( + Position::before(target), + vec![ + make.visibility_pub_crate().syntax().clone().into(), + make.whitespace(" ").into(), + ], + ); + } + *body_item = ast::Item::cast(editor.finish().new_root().clone()).unwrap(); } } @@ -451,6 +497,7 @@ impl Module { &mut self, module: Option, ctx: &AssistContext<'_, '_>, + make: &SyntaxFactory, ) -> Vec { let mut imports_to_remove = vec![]; let mut node_set = FxHashSet::default(); @@ -477,7 +524,8 @@ impl Module { }) .for_each(|(node, def)| { if node_set.insert(node.to_string()) - && let Some(import) = self.process_def_in_sel(def, &node, &module, ctx) + && let Some(import) = + self.process_def_in_sel(def, &node, &module, ctx, make) { check_intersection_and_push(&mut imports_to_remove, import); } @@ -493,6 +541,7 @@ impl Module { use_node: &SyntaxNode, curr_parent_module: &Option, ctx: &AssistContext<'_, '_>, + make: &SyntaxFactory, ) -> Option { //We only need to find in the current file let selection_range = ctx.selection_trimmed(); @@ -568,7 +617,7 @@ impl Module { // mod -> ust_stmt transversal // true | false -> super import insertion // true | true -> super import insertion - let super_use_node = make_use_stmt_of_node_with_super(use_node); + let super_use_node = make_use_stmt_of_node_with_super(use_node, make); self.use_items.insert(0, super_use_node); } None => {} @@ -591,14 +640,14 @@ impl Module { if !first_path_in_use_tree_str.contains("super") && !first_path_in_use_tree_str.contains("crate") { - let super_path = make::ext::ident_path("super"); + let super_path = make.ident_path("super"); use_tree_str.push(super_path); } } use_tree_paths = Some(use_tree_str); } else if def_in_mod && def_out_sel { - let super_use_node = make_use_stmt_of_node_with_super(use_node); + let super_use_node = make_use_stmt_of_node_with_super(use_node, make); self.use_items.insert(0, super_use_node); } } @@ -610,7 +659,7 @@ impl Module { && let Some(first_path_in_use_tree) = use_tree_paths.first() && first_path_in_use_tree.to_string().contains("super") { - use_tree_paths.insert(0, make::ext::ident_path("super")); + use_tree_paths.insert(0, make.ident_path("super")); } let is_item = matches!( @@ -625,12 +674,12 @@ impl Module { | Definition::TypeAlias(_) ); - if (def_out_sel || !is_item) && use_stmt_not_in_sel { - let use_ = make::use_( - None, - None, - make::use_tree(make::join_paths(use_tree_paths), None, None, false), - ); + if (def_out_sel || !is_item) + && use_stmt_not_in_sel + && let Some(joined) = + use_tree_paths.into_iter().reduce(|acc, p| make.path_concat(acc, p)) + { + let use_ = make.use_([], None, make.use_tree(joined, None, None, false)); self.use_items.insert(0, ast::Item::from(use_)); } } @@ -742,8 +791,7 @@ fn check_def_in_mod_and_out_sel( } fn get_replacements_for_visibility_change( - items: &mut [ast::Item], - is_clone_for_updated: bool, + items: &[ast::Item], ) -> ( Vec<(Option, SyntaxNode)>, Vec<(Option, SyntaxNode)>, @@ -754,9 +802,6 @@ fn get_replacements_for_visibility_change( let mut impls = Vec::new(); for item in items { - if !is_clone_for_updated { - *item = item.clone_for_update(); - } //Use stmts are ignored macro_rules! push_to_replacement { ($it:ident) => { @@ -813,15 +858,6 @@ fn get_use_tree_paths_from_path( Some(use_tree_str) } -fn add_change_vis(vis: Option, node_or_token_opt: Option) { - if vis.is_none() - && let Some(node_or_token) = node_or_token_opt - { - let pub_crate_vis = make::visibility_pub_crate().clone_for_update(); - ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax()); - } -} - fn indent_range_before_given_node(node: &SyntaxNode) -> Option { node.siblings_with_tokens(syntax::Direction::Prev) .find(|x| x.kind() == WHITESPACE) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 4a8c9d450c45c..d7f1844b132cf 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -286,16 +286,6 @@ impl ast::Use { } } -impl ast::Impl { - pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList { - if self.assoc_item_list().is_none() { - let assoc_item_list = make::assoc_item_list(None).clone_for_update(); - ted::append_child(self.syntax(), assoc_item_list.syntax()); - } - self.assoc_item_list().unwrap() - } -} - impl ast::RecordExprField { /// This will either replace the initializer, or in the case that this is a shorthand convert /// the initializer into the name ref and insert the expr as the new initializer. From de062d934dafa4563b49670473ce06032021d01c Mon Sep 17 00:00:00 2001 From: Kao-Wei Yeh Date: Mon, 8 Jun 2026 14:41:06 +0800 Subject: [PATCH 010/116] Make assist `inline_type_alias` work on ADT definitions --- .../src/handlers/inline_type_alias.rs | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs index e4a1314f5bb29..bb76e2743c377 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -135,7 +135,20 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_, '_>) PathResolution::SelfType(imp) => { concrete_type = imp.source(ctx.db())?.value.self_ty()?; } - // FIXME: should also work in ADT definitions + PathResolution::Def(hir::ModuleDef::Adt(adt)) => { + let make = SyntaxFactory::without_mappings(); + let src = adt.source(ctx.db())?.value; + let name = src.name()?; + let generic_params = src.generic_param_list(); + let name_ref = make.name_ref(&name.text()); + let segment = match generic_params { + Some(params) => { + make.path_segment_generics(name_ref, params.to_generic_args(&make)) + } + None => make.path_segment(name_ref), + }; + concrete_type = make.ty_path_from_segments([segment], false); + } _ => return None, } @@ -996,6 +1009,68 @@ trait Tr { ); } + #[test] + fn inline_self_type_in_adt_definition() { + check_assist( + inline_type_alias, + r#" +enum Foo { + A(i32), + B(Box), +} +"#, + r#" +enum Foo { + A(i32), + B(Box), +} +"#, + ); + check_assist( + inline_type_alias, + r#" +struct Foo { + a: Box, +} +"#, + r#" +struct Foo { + a: Box, +} +"#, + ); + check_assist( + inline_type_alias, + r#" +struct Foo { + a: T, + b: Box, +} +"#, + r#" +struct Foo { + a: T, + b: Box>, +} +"#, + ); + check_assist( + inline_type_alias, + r#" +union Foo { + a: u32, + b: std::mem::ManuallyDrop>, +} +"#, + r#" +union Foo { + a: u32, + b: std::mem::ManuallyDrop>, +} +"#, + ); + } + #[test] fn inline_types_with_lifetime() { check_assist( From f42e0022f447ba1d3fe684f9a41fd03a028e09a1 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 9 Jun 2026 17:24:05 +0800 Subject: [PATCH 011/116] feat: support flyimport exclude variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example --- ```json { "rust-analyzer.completion.autoimport.exclude": [ {"path": "xxx_crate::Foo", "type": "variants"}, ] } ``` ```rust enum Foo { Variant1, Variant2, } fn main() { V$0 } ``` **Before this PR** ``` ev TupleV(…) TupleV(u32) ev Variant1 (use Foo::Variant1) Variant1 ev Variant2 (use Foo::Variant2) Variant2 bt u32 u32 ``` **After this PR** ``` ev TupleV(…) TupleV(u32) bt u32 u32 ``` --- .../crates/ide-completion/src/config.rs | 1 + .../crates/ide-completion/src/context.rs | 12 ++++ .../ide-completion/src/tests/expression.rs | 70 +++++++++++++++++++ .../crates/rust-analyzer/src/config.rs | 9 ++- .../docs/book/src/configuration_generated.md | 3 + .../rust-analyzer/editors/code/package.json | 5 +- 6 files changed, 97 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index ac52c816e52a9..0739084381b3b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -45,6 +45,7 @@ pub enum AutoImportExclusionType { Always, Methods, SubItems, + Variants, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index f7bb14391b7de..507ecaff0dca0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -868,10 +868,22 @@ impl<'a, 'db> CompletionContext<'a, 'db> { _ => None, }) .collect::>(); + let exclude_variants = exclude_flyimport + .iter() + .flat_map(|it| match it { + (ModuleDef::Adt(hir::Adt::Enum(enum_)), AutoImportExclusionType::Variants) => { + enum_.variants(db) + } + _ => vec![], + }) + .collect::>(); exclude_flyimport .extend(exclude_traits.iter().map(|&t| (t.into(), AutoImportExclusionType::Always))); exclude_flyimport .extend(exclude_subitems.into_iter().map(|it| (it, AutoImportExclusionType::Always))); + exclude_flyimport.extend( + exclude_variants.into_iter().map(|it| (it.into(), AutoImportExclusionType::Always)), + ); // FIXME: This should be part of `CompletionAnalysis` / `expand_and_analyze` let complete_semicolon = if !config.add_semicolon_to_unit { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index e49afa66ad738..57f067dc94768 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -3041,6 +3041,76 @@ fn foo() { ); } +#[test] +fn flyimport_excluded_enum_variants_from_flyimport() { + check_with_config( + CompletionConfig { + exclude_flyimport: vec![( + "ra_test_fixture::Foo".to_owned(), + AutoImportExclusionType::Variants, + )], + ..TEST_CONFIG + }, + r#" +enum Foo { + Variant1, + Variant2, +} +fn foo() { + V$0 +} + "#, + expect![[r#" + ct CONST Unit + en Enum Enum + en Foo Foo + fn foo() fn() + fn function() fn() + ma makro!(…) macro_rules! makro + md module:: + sc STATIC Unit + st Record Record + st Tuple Tuple + st Unit Unit + un Union Union + ev TupleV(…) TupleV(u32) + bt u32 u32 + kw async + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + #[test] fn excluded_trait_method_is_excluded_from_path_completion() { check_with_config( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 74ba183f97ddb..4ea447333903d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -665,6 +665,9 @@ config_data! { /// For modules the type "sub_items" can be used to only exclude the all items in it but not the module /// itself. This does not include items defined in nested modules. /// + /// For enums the type "variants" can be used to only exclude the all variants in it but not the enum + /// itself. + /// /// This setting also inherits `#rust-analyzer.completion.excludeTraits#`. completion_autoimport_exclude: Vec = vec![ AutoImportExclusion::Verbose { path: "core::borrow::Borrow".to_owned(), r#type: AutoImportExclusionType::Methods }, @@ -1944,6 +1947,9 @@ impl Config { AutoImportExclusionType::SubItems => { ide_completion::AutoImportExclusionType::SubItems } + AutoImportExclusionType::Variants => { + ide_completion::AutoImportExclusionType::Variants + } }, ), }) @@ -3004,6 +3010,7 @@ pub enum AutoImportExclusionType { Always, Methods, SubItems, + Variants, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -4135,7 +4142,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json }, "type": { "type": "string", - "enum": ["always", "methods", "sub_items"], + "enum": ["always", "methods", "sub_items", "variants"], "enumDescriptions": [ "Do not show this item or its methods (if it is a trait) in auto-import completions.", "Do not show this trait's methods in auto-import completions.", diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index bc5ef9e96c02a..76b626b09fb5b 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -449,6 +449,9 @@ itself. For modules the type "sub_items" can be used to only exclude the all items in it but not the module itself. This does not include items defined in nested modules. +For enums the type "variants" can be used to only exclude the all variants in it but not the enum +itself. + This setting also inherits `#rust-analyzer.completion.excludeTraits#`. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index cb328e8866e26..7bc8fda65985e 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1333,7 +1333,7 @@ "title": "Completion", "properties": { "rust-analyzer.completion.autoimport.exclude": { - "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more\nverbose form `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait\nitself.\n\nFor modules the type \"sub_items\" can be used to only exclude the all items in it but not the module\nitself. This does not include items defined in nested modules.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", + "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more\nverbose form `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait\nitself.\n\nFor modules the type \"sub_items\" can be used to only exclude the all items in it but not the module\nitself. This does not include items defined in nested modules.\n\nFor enums the type \"variants\" can be used to only exclude the all variants in it but not the enum\nitself.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", "default": [ { "path": "core::borrow::Borrow", @@ -1361,7 +1361,8 @@ "enum": [ "always", "methods", - "sub_items" + "sub_items", + "variants" ], "enumDescriptions": [ "Do not show this item or its methods (if it is a trait) in auto-import completions.", From c965932b218a62670664001da68450a4200b802f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 9 Jun 2026 18:44:46 +0800 Subject: [PATCH 012/116] fix: supports inline variable in macro Example --- ```rust macro_rules! m { ($i:expr) => { $i } } fn f() { let xyz = 0; m!(xyz$0); } ``` **Before this PR** Assist not applicable **After this PR** ```rust macro_rules! m { ($i:expr) => { $i } } fn f() { m!(0); } ``` --- .../src/handlers/inline_local_variable.rs | 137 +++++++++--------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs index 531adf62ba3f5..d94632b56c958 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs @@ -1,19 +1,20 @@ use either::{Either, for_both}; use hir::{PathResolution, Semantics}; use ide_db::{ - EditionedFileId, RootDatabase, + RootDatabase, defs::Definition, - search::{FileReference, FileReferenceNode, UsageSearchResult}, + search::{FileReference, UsageSearchResult}, }; use syntax::{ - Direction, TextRange, + Direction, T, TextRange, ast::{self, AstNode, AstToken, HasName}, - syntax_editor::{Element, SyntaxEditor}, + syntax_editor::{Element, Position, SyntaxEditor}, }; use crate::{ AssistId, assist_context::{AssistContext, Assists}, + utils::cover_edit_range, }; // Assist: inline_local_variable @@ -33,13 +34,13 @@ use crate::{ // } // ``` pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> { - let file_id = ctx.file_id(); + let source = ctx.source_file().syntax(); let range = ctx.selection_trimmed(); let InlineData { let_stmt, delete_let, references, target } = - if let Some(path_expr) = ctx.find_node_at_offset::() { - inline_usage(&ctx.sema, path_expr, range, file_id) + if let Some(path_expr) = ctx.find_node_at_offset_with_descend::() { + inline_usage(&ctx.sema, path_expr, range) } else if let Some(let_stmt) = ctx.find_node_at_offset() { - inline_let(&ctx.sema, let_stmt, range, file_id) + inline_let(&ctx.sema, let_stmt, range) } else { None }?; @@ -47,47 +48,29 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, ' either::Either::Left(it) => it.initializer()?, either::Either::Right(it) => it.expr()?, }; - - let wrap_in_parens = references - .into_iter() - .filter_map(|FileReference { range, name, .. }| match name { - FileReferenceNode::NameRef(name) => Some((range, name)), - _ => None, - }) - .map(|(range, name_ref)| { - if range != name_ref.syntax().text_range() { - // Do not rename inside macros - // FIXME: This feels like a bad heuristic for macros - return None; + let needs_parens = |name_ref: &ast::NameRef| { + let usage_node = + name_ref.syntax().ancestors().find(|it| ast::PathExpr::can_cast(it.kind())); + let usage_parent = usage_node.as_ref().and_then(|it| it.parent()); + match (usage_node, usage_parent) { + (Some(usage), Some(parent)) => { + initializer_expr.needs_parens_in_place_of(&parent, &usage) } - let usage_node = - name_ref.syntax().ancestors().find(|it| ast::PathExpr::can_cast(it.kind())); - let usage_parent_option = usage_node.as_ref().and_then(|it| it.parent()); - let usage_parent = match usage_parent_option { - Some(u) => u, - None => return Some((name_ref, false)), - }; - let should_wrap = initializer_expr - .needs_parens_in_place_of(&usage_parent, usage_node.as_ref().unwrap()); - Some((name_ref, should_wrap)) - }) - .collect::>>()?; - - let target = match target { - ast::NameOrNameRef::Name(it) => it.syntax().clone(), - ast::NameOrNameRef::NameRef(it) => it.syntax().clone(), + _ => false, + } }; acc.add( AssistId::refactor_inline("inline_local_variable"), "Inline variable", - target.text_range(), - move |builder| { - let editor = builder.make_editor(&target); + target.range, + |builder| { + let editor = builder.make_editor(source); let make = editor.make(); if delete_let { editor.delete(let_stmt.syntax()); + // Processing let-expr in let-chain if let Some(bin_expr) = let_stmt.syntax().parent().and_then(ast::BinExpr::cast) && let Some(op_token) = bin_expr.op_token() { @@ -99,19 +82,27 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, ' } } - for (name, should_wrap) in wrap_in_parens { - let replacement = if should_wrap { + for FileReference { range, name, .. } in references { + let Some(name) = name.as_name_ref().cloned() else { continue }; + let replacement = if needs_parens(&name) { make.expr_paren(initializer_expr.clone()).into() } else { initializer_expr.clone() }; - if let Some(record_field) = ast::RecordExprField::for_field_name(&name) { + let place = cover_edit_range(source, range); + if ast::RecordExprField::for_field_name(&name).is_some() { cov_mark::hit!(inline_field_shorthand); - let replacement = make.record_expr_field(name, Some(replacement)); - editor.replace(record_field.syntax(), replacement.syntax()); + editor.insert_all( + Position::after(place.end()), + vec![ + make.token(T![:]).into(), + make.whitespace(" ").into(), + replacement.syntax().clone().into(), + ], + ); } else { - editor.replace(name.syntax(), replacement.syntax()); + editor.replace_all(place, vec![replacement.syntax().clone().into()]); } } builder.add_file_edits(ctx.vfs_file_id(), editor); @@ -122,7 +113,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, ' struct InlineData { let_stmt: Either, delete_let: bool, - target: ast::NameOrNameRef, + target: hir::FileRange, references: Vec, } @@ -130,7 +121,6 @@ fn inline_let( sema: &Semantics<'_, RootDatabase>, let_stmt: Either, range: TextRange, - file_id: EditionedFileId, ) -> Option { let bind_pat = match for_both!(&let_stmt, it => it.pat())? { ast::Pat::IdentPat(pat) => pat, @@ -140,20 +130,18 @@ fn inline_let( cov_mark::hit!(test_not_inline_mut_variable); return None; } - if !bind_pat.syntax().text_range().contains_range(range) { + let target = sema.original_range_opt(bind_pat.name()?.syntax())?; + if !target.range.contains_range(range) { cov_mark::hit!(not_applicable_outside_of_bind_pat); return None; } let local = sema.to_def(&bind_pat)?; - let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all(); - match references.remove(&file_id) { - Some(references) => Some(InlineData { - let_stmt, - delete_let: true, - target: ast::NameOrNameRef::Name(bind_pat.name()?), - references, - }), + let UsageSearchResult { references } = Definition::Local(local).usages(sema).all(); + let references = references.into_iter().flat_map(|it| it.1).collect::>(); + + match references.first() { + Some(_) => Some(InlineData { let_stmt, delete_let: true, target, references }), None => { cov_mark::hit!(test_not_applicable_if_variable_unused); None @@ -165,11 +153,11 @@ fn inline_usage( sema: &Semantics<'_, RootDatabase>, path_expr: ast::PathExpr, range: TextRange, - file_id: EditionedFileId, ) -> Option { let path = path_expr.path()?; let name = path.as_single_name_ref()?; - if !name.syntax().text_range().contains_range(range) { + let target = sema.original_range_opt(name.syntax())?; + if !target.range.contains_range(range) { cov_mark::hit!(test_not_inline_selection_too_broad); return None; } @@ -193,12 +181,12 @@ fn inline_usage( let let_stmt = AstNode::cast(bind_pat.syntax().parent()?)?; - let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all(); - let mut references = references.remove(&file_id)?; + let UsageSearchResult { references } = Definition::Local(local).usages(sema).all(); + let mut references = references.into_iter().flat_map(|it| it.1).collect::>(); let delete_let = references.len() == 1; references.retain(|fref| fref.name.as_name_ref() == Some(&name)); - Some(InlineData { let_stmt, delete_let, target: ast::NameOrNameRef::NameRef(name), references }) + Some(InlineData { let_stmt, delete_let, target, references }) } fn remove_whitespace(elem: impl Element, dir: Direction, editor: &SyntaxEditor) { @@ -969,8 +957,8 @@ fn main() { } #[test] - fn not_applicable_on_local_usage_in_macro() { - check_assist_not_applicable( + fn local_usage_in_macro() { + check_assist( inline_local_variable, r#" macro_rules! m { @@ -978,11 +966,19 @@ macro_rules! m { } fn f() { let xyz = 0; - m!(xyz$0); // replacing it would break the macro + m!(xyz$0); // some macros may break, but it's best to support them +} +"#, + r#" +macro_rules! m { + ($i:ident) => { $i } +} +fn f() { + m!(0); // some macros may break, but it's best to support them } "#, ); - check_assist_not_applicable( + check_assist( inline_local_variable, r#" macro_rules! m { @@ -990,10 +986,19 @@ macro_rules! m { } fn f() { let xyz$0 = 0; - m!(xyz); // replacing it would break the macro + m!(xyz); // some macros may break, but it's best to support them +} +"#, + r#" +macro_rules! m { + ($i:ident) => { $i } +} +fn f() { + m!(0); // some macros may break, but it's best to support them } "#, ); + // FIXME: supports let-stmt inside macro case } #[test] From 54577e7f0bcf04dbd17f996d115b104a5554a0fe Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 9 Jun 2026 19:56:55 +0800 Subject: [PATCH 013/116] fix: do not panic variable def in macro Example --- ```rust macro_rules! i { ($($t:tt)*) => { $($t)* } } fn f() { i!(let xyz = 0;); _ = xyz$0; _ = xyz; } ``` **Before this PR** ``` request handler panicked: can't resolve SyntaxNodePtr { kind: LET_STMT, range: 0..9 } with SOURCE_FILE@0..108 ``` **After this PR** ```rust macro_rules! i { ($($t:tt)*) => { $($t)* } } fn f() { i!(let xyz = 0;); _ = 0; _ = xyz; } ``` --- .../src/handlers/inline_local_variable.rs | 82 +++++++++++++++++-- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs index d94632b56c958..7fba1ef057bdf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs @@ -39,7 +39,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, ' let InlineData { let_stmt, delete_let, references, target } = if let Some(path_expr) = ctx.find_node_at_offset_with_descend::() { inline_usage(&ctx.sema, path_expr, range) - } else if let Some(let_stmt) = ctx.find_node_at_offset() { + } else if let Some(let_stmt) = ctx.find_node_at_offset_with_descend() { inline_let(&ctx.sema, let_stmt, range) } else { None @@ -67,18 +67,20 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, ' |builder| { let editor = builder.make_editor(source); let make = editor.make(); - if delete_let { - editor.delete(let_stmt.syntax()); + if delete_let && let Some(original) = ctx.sema.original_range_opt(let_stmt.syntax()) { + let place = cover_edit_range(source, original.range); + editor.delete_all(place.clone()); // Processing let-expr in let-chain + // FIXME: process let-expr in macro, but this case is very rare if let Some(bin_expr) = let_stmt.syntax().parent().and_then(ast::BinExpr::cast) && let Some(op_token) = bin_expr.op_token() { editor.delete(&op_token); remove_whitespace(op_token, Direction::Prev, &editor); - remove_whitespace(let_stmt.syntax(), Direction::Prev, &editor); + remove_whitespace(place.start(), Direction::Prev, &editor); } else { - remove_whitespace(let_stmt.syntax(), Direction::Next, &editor); + remove_whitespace(place.end(), Direction::Next, &editor); } } @@ -998,7 +1000,75 @@ fn f() { } "#, ); - // FIXME: supports let-stmt inside macro case + } + + #[test] + fn local_def_in_macro() { + check_assist( + inline_local_variable, + r#" +macro_rules! i { + ($($t:tt)*) => { $($t)* } +} +fn f() { + i!(let xyz = 0;); + _ = xyz$0; +} +"#, + r#" +macro_rules! i { + ($($t:tt)*) => { $($t)* } +} +fn f() { + i!(); + _ = 0; +} +"#, + ); + check_assist( + inline_local_variable, + r#" +macro_rules! i { + ($($t:tt)*) => { $($t)* } +} +fn f() { + i!(let xyz = 0;); + _ = xyz$0; + _ = xyz; +} +"#, + r#" +macro_rules! i { + ($($t:tt)*) => { $($t)* } +} +fn f() { + i!(let xyz = 0;); + _ = 0; + _ = xyz; +} +"#, + ); + check_assist( + inline_local_variable, + r#" +macro_rules! i { + ($($t:tt)*) => { $($t)* } +} +fn f() { + i!(let $0xyz = 0;); + _ = xyz; +} +"#, + r#" +macro_rules! i { + ($($t:tt)*) => { $($t)* } +} +fn f() { + i!(); + _ = 0; +} +"#, + ); } #[test] From 2f67dec5817ba1dcc2985f1edaa241069392b06b Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 11 Jun 2026 03:12:14 +0800 Subject: [PATCH 014/116] internal: git ignore .vim/coc-settings.json --- src/tools/rust-analyzer/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore index 3beabe39bc7a3..32374dac91818 100644 --- a/src/tools/rust-analyzer/.gitignore +++ b/src/tools/rust-analyzer/.gitignore @@ -7,6 +7,7 @@ vendor/ *.log *.iml .vscode/settings.json +.vim/coc-settings.json .DS_Store /out/ /dump.lsif From 87443b694e86e8603270e442637d3df6bc372263 Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 10 Jun 2026 12:59:54 -0700 Subject: [PATCH 015/116] Remove docs about removed `analysis-bench` command This command as removed in 797185e1b66fb0d6ec1dedf206616890b5e3fef3. --- .../rust-analyzer/docs/book/src/contributing/README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/README.md b/src/tools/rust-analyzer/docs/book/src/contributing/README.md index bb2b6081ad956..d3e2acd9f7307 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/README.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/README.md @@ -206,13 +206,6 @@ To measure time for from-scratch analysis, use something like this: cargo run --release -p rust-analyzer -- analysis-stats ../chalk/ ``` -For measuring time of incremental analysis, use either of these: - -```bash -cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --highlight ../chalk/chalk-engine/src/logic.rs -cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --complete ../chalk/chalk-engine/src/logic.rs:94:0 -``` - Look for `fn benchmark_xxx` tests for a quick way to reproduce performance problems. ## Release Process From 18e250053442cb40df17fa7c30534f2712fcc308 Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 10 Jun 2026 13:56:11 -0700 Subject: [PATCH 016/116] Create directory for xtask metrics rustc_tests In c0f428d55b425c8ba18039a3687cdcdc47e111d1 this code was adjusted to handle a change in `load_workspace`. The change assumed that the `ra-rustc-test` folder existed in the `std::env::temp_dir`, but this assumption is not always correct. --- .../rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 49f28352b6cf6..69405b421eca5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -64,6 +64,7 @@ impl Tester { fn new() -> Result { let mut path = AbsPathBuf::assert_utf8(std::env::temp_dir()); path.push("ra-rustc-test"); + std::fs::create_dir_all(&path)?; let tmp_file = path.join("ra-rustc-test.rs"); std::fs::write(&tmp_file, "")?; let cargo_config = CargoConfig { From 51f41825072a6245e3df612f7dfe76d87e1c9b30 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 11 Jun 2026 05:40:22 +0000 Subject: [PATCH 017/116] Prepare for merging from rust-lang/rust This updates the rust-version file to 485ec3fbcc12fa14ef6596dabb125ad710499c9e. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 387bd8edd2196..5bdff8eb64eec 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -029c9e18dd1f4668e1d42bb187c1c263dfe20093 +485ec3fbcc12fa14ef6596dabb125ad710499c9e From 6536d21a9f1952ed7f0465f05321ca5123074010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 11 Jun 2026 10:57:27 +0300 Subject: [PATCH 018/116] Revert default feature --- src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 72d394d37bfd4..68e0bb6ac8a50 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -35,7 +35,7 @@ line-index.workspace = true proc-macro-test.path = "./proc-macro-test" [features] -default = ["in-rust-tree"] +default = [] in-rust-tree = [] [lints] From cda17e1f777f2f823e60954ffa203b1171f04b20 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 11 Jun 2026 16:05:42 +0800 Subject: [PATCH 019/116] Add original file_id check --- .../src/handlers/inline_local_variable.rs | 29 +++++++++++-------- .../crates/ide-assists/src/utils.rs | 9 ++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs index 7fba1ef057bdf..7a82e8b2f3ac8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs @@ -1,5 +1,5 @@ use either::{Either, for_both}; -use hir::{PathResolution, Semantics}; +use hir::{EditionedFileId, PathResolution, Semantics}; use ide_db::{ RootDatabase, defs::Definition, @@ -14,7 +14,7 @@ use syntax::{ use crate::{ AssistId, assist_context::{AssistContext, Assists}, - utils::cover_edit_range, + utils::{cover_edit_range, original_range_in}, }; // Assist: inline_local_variable @@ -34,13 +34,14 @@ use crate::{ // } // ``` pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> { + let file_id = ctx.file_id(); let source = ctx.source_file().syntax(); let range = ctx.selection_trimmed(); let InlineData { let_stmt, delete_let, references, target } = if let Some(path_expr) = ctx.find_node_at_offset_with_descend::() { - inline_usage(&ctx.sema, path_expr, range) + inline_usage(&ctx.sema, path_expr, range, file_id) } else if let Some(let_stmt) = ctx.find_node_at_offset_with_descend() { - inline_let(&ctx.sema, let_stmt, range) + inline_let(&ctx.sema, let_stmt, range, file_id) } else { None }?; @@ -63,12 +64,14 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, ' acc.add( AssistId::refactor_inline("inline_local_variable"), "Inline variable", - target.range, + target, |builder| { let editor = builder.make_editor(source); let make = editor.make(); - if delete_let && let Some(original) = ctx.sema.original_range_opt(let_stmt.syntax()) { - let place = cover_edit_range(source, original.range); + if delete_let + && let Some(original) = original_range_in(file_id, &ctx.sema, let_stmt.syntax()) + { + let place = cover_edit_range(source, original); editor.delete_all(place.clone()); // Processing let-expr in let-chain @@ -115,7 +118,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, ' struct InlineData { let_stmt: Either, delete_let: bool, - target: hir::FileRange, + target: TextRange, references: Vec, } @@ -123,6 +126,7 @@ fn inline_let( sema: &Semantics<'_, RootDatabase>, let_stmt: Either, range: TextRange, + file_id: EditionedFileId, ) -> Option { let bind_pat = match for_both!(&let_stmt, it => it.pat())? { ast::Pat::IdentPat(pat) => pat, @@ -132,8 +136,8 @@ fn inline_let( cov_mark::hit!(test_not_inline_mut_variable); return None; } - let target = sema.original_range_opt(bind_pat.name()?.syntax())?; - if !target.range.contains_range(range) { + let target = original_range_in(file_id, sema, bind_pat.name()?.syntax())?; + if !target.contains_range(range) { cov_mark::hit!(not_applicable_outside_of_bind_pat); return None; } @@ -155,11 +159,12 @@ fn inline_usage( sema: &Semantics<'_, RootDatabase>, path_expr: ast::PathExpr, range: TextRange, + file_id: EditionedFileId, ) -> Option { let path = path_expr.path()?; let name = path.as_single_name_ref()?; - let target = sema.original_range_opt(name.syntax())?; - if !target.range.contains_range(range) { + let target = original_range_in(file_id, sema, name.syntax())?; + if !target.contains_range(range) { cov_mark::hit!(test_not_inline_selection_too_broad); return None; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 1b6c9a579aba0..086f54ed17f69 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1177,6 +1177,15 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo is_const } +pub(crate) fn original_range_in( + file_id: hir::EditionedFileId, + sema: &Semantics<'_, RootDatabase>, + value: &SyntaxNode, +) -> Option { + let original = sema.original_range_opt(value)?; + (original.file_id == file_id).then_some(original.range) +} + // FIXME: #20460 When hir-ty can analyze the `never` statement at the end of block, remove it pub(crate) fn is_never_block( sema: &Semantics<'_, RootDatabase>, From fe1dce17b002bd800293e64881536cf011184cf4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 11 Jun 2026 13:48:55 +0200 Subject: [PATCH 020/116] Fix destructuring assignments not introducing moves --- .../closure/analysis/expr_use_visitor.rs | 3 +- .../hir-ty/src/tests/closure_captures.rs | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index 34f9508e763f0..d8a8cceee6583 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -1016,8 +1016,9 @@ impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { } } Pat::Expr(expr) => { - // Destructuring assignment. this.mutate_expr(expr)?; + // Destructuring assignment moves + this.consume_or_copy(place); } Pat::Or(_) | Pat::Box { .. } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index 3942a7ae27afa..bf0e60cf21b80 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -617,3 +617,40 @@ fn foo(foo: &Foo) { expect!["102..126;85..88;114..117 ByRef(Immutable) *foo &' Foo"], ); } + +#[test] +fn method_call_field_access_regression() { + check_closure_captures( + r#" +//- minicore:copy, fn +struct NonCopy; + +struct Wrapper { + field: NonCopy, +} + +impl Wrapper { + fn wrapped(&self) -> NonCopy { + NonCopy + } +} + +pub struct Wrapper2 { + field1: NonCopy, + field2: NonCopy, +} + +fn fun(wrapper: Wrapper) { + pub fn update(_: impl FnOnce(&mut T)) { + todo!() + } + + update::(|this| { + this.field1 = wrapper.wrapped(); + this.field2 = wrapper.field; + }); +} + "#, + expect!["319..411;206..213;350..357,391..398 ByValue wrapper Wrapper"], + ); +} From 7be87edcb3fbdb060d9d867c9f4fb477f5e019ed Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Thu, 11 Jun 2026 19:47:14 -0300 Subject: [PATCH 021/116] Don't ICE on non-lifetime binders under `-Zassumptions-on-binders` The region-constraint machinery for `-Zassumptions-on-binders` is region-outlives-only. A non-lifetime binder (`for`) introduces a placeholder type in the binder's universe `u`. The rewrite that pulls constraints out of `u` only folds regions (`PlaceholderReplacer` just implements `fold_region`), so an alias-outlives constraint such as `::Assoc: 'r` reaches `pull_region_outlives_constraints_out_of_universe` still in `u` and trips `assert!(max_universe < u)`. Report ambiguity for those constraints instead of asserting, matching the existing `None => Ambiguity` bail-outs in this module. The goal then surfaces as an ordinary ambiguity error rather than an ICE. --- .../rustc_type_ir/src/region_constraint.rs | 14 +++++++++++-- .../non_lifetime_binder_alias_outlives.rs | 21 +++++++++++++++++++ .../non_lifetime_binder_alias_outlives.stderr | 20 ++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.rs create mode 100644 tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.stderr diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 43b1535d16809..b896d7a398178 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -654,8 +654,18 @@ fn pull_region_outlives_constraints_out_of_universe< use RegionConstraint::*; match constraint { Ambiguity | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => { - assert!(max_universe(infcx, constraint.clone()) < u); - constraint + // With only lifetime binders the rewrite step lowers these constraints out of `u` + // (or destructures them), so we expect `max_universe < u` here. A non-lifetime + // binder (`for`) instead introduces a placeholder type in `u`, which + // `PlaceholderReplacer` (region-only, see its `fold_region`) cannot pull out, + // leaving e.g. `::Assoc: 'r` stranded in `u`. The assumptions-on-binders + // machinery is region-outlives-only and can't decide such a constraint, so report + // ambiguity rather than ICE. + if max_universe(infcx, constraint.clone()) < u { + constraint + } else { + RegionConstraint::Ambiguity + } } RegionOutlives(region_1, region_2) => { let region_1_u = max_universe(infcx, region_1); diff --git a/tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.rs b/tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.rs new file mode 100644 index 0000000000000..8178575555383 --- /dev/null +++ b/tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver -Zassumptions-on-binders + +// Regression test for #157778. +// +// A non-lifetime binder (`for`) introduces a placeholder *type* in universe `u`. The +// resulting alias-outlives constraint `::Assoc: 'r` stays in `u` because the +// region-only rewrite (`PlaceholderReplacer` only folds regions) cannot pull a type +// placeholder out of `u`. This used to trip an `assert!(max_universe < u)` and ICE in +// `pull_region_outlives_constraints_out_of_universe`. The assumptions-on-binders machinery +// is region-outlives-only, so we now report ambiguity instead of panicking. + +#![feature(non_lifetime_binders)] + +trait Trait { + type Assoc; + type Ref //~ ERROR cannot satisfy `::Assoc: 'static` + where + for T: Trait; +} + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.stderr b/tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.stderr new file mode 100644 index 0000000000000..3b8c8720c6774 --- /dev/null +++ b/tests/ui/assumptions_on_binders/non_lifetime_binder_alias_outlives.stderr @@ -0,0 +1,20 @@ +error[E0284]: type annotations needed: cannot satisfy `::Assoc: 'static` + --> $DIR/non_lifetime_binder_alias_outlives.rs:16:5 + | +LL | / type Ref +LL | | where +LL | | for T: Trait; + | |________________________________________^ cannot satisfy `::Assoc: 'static` + | +note: required by a bound in `Trait::Ref` + --> $DIR/non_lifetime_binder_alias_outlives.rs:18:32 + | +LL | type Ref + | --- required by a bound in this associated type +LL | where +LL | for T: Trait; + | ^^^^^^^ required by this bound in `Trait::Ref` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. From e7be4162b00e1ca95f74cbe76677e5ed246a0179 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 May 2026 00:03:33 +0530 Subject: [PATCH 022/116] remove all the ted based and editor based API's from edit_in_place --- .../crates/syntax/src/ast/edit_in_place.rs | 308 +----------------- 1 file changed, 8 insertions(+), 300 deletions(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index d7f1844b132cf..4a38cb8198e3f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -1,308 +1,16 @@ //! Structural editing for ast. - -use std::iter::{empty, once, successors}; - -use parser::T; - use crate::{ - AstNode, AstToken, Direction, - algo::{self, neighbor}, - ast::{self, make, syntax_factory::SyntaxFactory}, - syntax_editor::SyntaxEditor, + AstNode, + ast::{self, make}, ted, }; -use super::HasName; - -impl ast::GenericParamList { - /// Constructs a matching [`ast::GenericArgList`] - pub fn to_generic_args(&self, make: &SyntaxFactory) -> ast::GenericArgList { - let args = self.generic_params().filter_map(|param| match param { - ast::GenericParam::LifetimeParam(it) => { - Some(ast::GenericArg::LifetimeArg(make.lifetime_arg(it.lifetime()?))) - } - ast::GenericParam::TypeParam(it) => { - Some(ast::GenericArg::TypeArg(make.type_arg(make.ty_name(it.name()?)))) - } - ast::GenericParam::ConstParam(it) => { - // Name-only const params get parsed as `TypeArg`s - Some(ast::GenericArg::TypeArg(make.type_arg(make.ty_name(it.name()?)))) - } - }); - - make::generic_arg_list(args) - } -} - -pub trait Removable: AstNode { - fn remove(&self); -} - -impl Removable for ast::UseTree { - fn remove(&self) { - for dir in [Direction::Next, Direction::Prev] { - if let Some(next_use_tree) = neighbor(self, dir) { - let separators = self - .syntax() - .siblings_with_tokens(dir) - .skip(1) - .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); - ted::remove_all_iter(separators); - break; - } - } - ted::remove(self.syntax()); - } -} - -impl ast::UseTree { - /// Editor variant of UseTree remove - fn remove_with_editor(&self, editor: &SyntaxEditor) { - for dir in [Direction::Next, Direction::Prev] { - if let Some(next_use_tree) = neighbor(self, dir) { - let separators = self - .syntax() - .siblings_with_tokens(dir) - .skip(1) - .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); - for separator in separators { - editor.delete(separator); - } - break; - } - } - editor.delete(self.syntax()); - } - - /// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty. - pub fn remove_recursive(self, editor: &SyntaxEditor) { - let parent = self.syntax().parent(); - - if let Some(u) = parent.clone().and_then(ast::Use::cast) { - u.remove(editor); - } else if let Some(u) = parent.and_then(ast::UseTreeList::cast) { - if u.use_trees().nth(1).is_none() - || u.use_trees().all(|use_tree| { - use_tree.syntax() == self.syntax() || editor.deleted(use_tree.syntax()) - }) - { - u.parent_use_tree().remove_recursive(editor); - return; - } - self.remove_with_editor(editor); - u.remove_unnecessary_braces(editor); - } - } - - pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList { - match self.use_tree_list() { - Some(it) => it, - None => { - let position = ted::Position::last_child_of(self.syntax()); - let use_tree_list = make::use_tree_list(empty()).clone_for_update(); - let mut elements = Vec::with_capacity(2); - if self.coloncolon_token().is_none() { - elements.push(make::token(T![::]).into()); - } - elements.push(use_tree_list.syntax().clone().into()); - ted::insert_all_raw(position, elements); - use_tree_list - } - } - } - - /// Splits off the given prefix, making it the path component of the use tree, - /// appending the rest of the path to all UseTreeList items. - /// - /// # Examples - /// - /// `prefix$0::suffix` -> `prefix::{suffix}` - /// - /// `prefix$0` -> `prefix::{self}` - /// - /// `prefix$0::*` -> `prefix::{*}` - pub fn split_prefix(&self, prefix: &ast::Path) { - debug_assert_eq!(self.path(), Some(prefix.top_path())); - let path = self.path().unwrap(); - if &path == prefix && self.use_tree_list().is_none() { - if self.star_token().is_some() { - // path$0::* -> * - if let Some(a) = self.coloncolon_token() { - ted::remove(a) - } - ted::remove(prefix.syntax()); - } else { - // path$0 -> self - let self_suffix = - make::path_unqualified(make::path_segment_self()).clone_for_update(); - ted::replace(path.syntax(), self_suffix.syntax()); - } - } else if split_path_prefix(prefix).is_none() { - return; - } - // At this point, prefix path is detached; _self_ use tree has suffix path. - // Next, transform 'suffix' use tree into 'prefix::{suffix}' - let subtree = self.clone_subtree().clone_for_update(); - ted::remove_all_iter(self.syntax().children_with_tokens()); - ted::insert(ted::Position::first_child_of(self.syntax()), prefix.syntax()); - self.get_or_create_use_tree_list().add_use_tree(subtree); - - fn split_path_prefix(prefix: &ast::Path) -> Option<()> { - let parent = prefix.parent_path()?; - let segment = parent.segment()?; - if algo::has_errors(segment.syntax()) { - return None; - } - for p in successors(parent.parent_path(), |it| it.parent_path()) { - p.segment()?; - } - if let Some(a) = prefix.parent_path().and_then(|p| p.coloncolon_token()) { - ted::remove(a) - } - ted::remove(prefix.syntax()); - Some(()) - } - } - - /// Editor variant of `split_prefix` - pub fn split_prefix_with_editor(&self, editor: &SyntaxEditor, prefix: &ast::Path) { - debug_assert_eq!(self.path(), Some(prefix.top_path())); - - let make = editor.make(); - let path = self.path().unwrap(); - let suffix = if path == *prefix && self.use_tree_list().is_none() { - if self.star_token().is_some() { - make.use_tree_glob() - } else { - let self_path = make.path_unqualified(make.path_segment_self()); - make.use_tree(self_path, None, None, false) - } - } else { - let suffix_segments = path.segments().skip(prefix.segments().count()); - let suffix_path = make.path_from_segments(suffix_segments, false); - make.use_tree( - suffix_path, - self.use_tree_list(), - self.rename(), - self.star_token().is_some(), - ) - }; - let use_tree_list = make.use_tree_list(once(suffix)); - let new_use_tree = make.use_tree(prefix.clone(), Some(use_tree_list), None, false); - - editor.replace(self.syntax(), new_use_tree.syntax()); - } - - /// Wraps the use tree in use tree list with no top level path (if it isn't already). - /// - /// # Examples - /// - /// `foo::bar` -> `{foo::bar}` - /// - /// `{foo::bar}` -> `{foo::bar}` - pub fn wrap_in_tree_list(&self) -> Option<()> { - if self.use_tree_list().is_some() - && self.path().is_none() - && self.star_token().is_none() - && self.rename().is_none() - { - return None; - } - let subtree = self.clone_subtree().clone_for_update(); - ted::remove_all_iter(self.syntax().children_with_tokens()); - ted::append_child( - self.syntax(), - make::use_tree_list(once(subtree)).clone_for_update().syntax(), - ); - Some(()) - } -} - -impl ast::UseTreeList { - pub fn add_use_tree(&self, use_tree: ast::UseTree) { - let (position, elements) = match self.use_trees().last() { - Some(last_tree) => ( - ted::Position::after(last_tree.syntax()), - vec![ - make::token(T![,]).into(), - make::tokens::single_space().into(), - use_tree.syntax.into(), - ], - ), - None => { - let position = match self.l_curly_token() { - Some(l_curly) => ted::Position::after(l_curly), - None => ted::Position::last_child_of(self.syntax()), - }; - (position, vec![use_tree.syntax.into()]) - } - }; - ted::insert_all_raw(position, elements); - } -} - -impl ast::Use { - fn remove(&self, editor: &SyntaxEditor) { - let make = editor.make(); - let next_ws = self - .syntax() - .next_sibling_or_token() - .and_then(|it| it.into_token()) - .and_then(ast::Whitespace::cast); - if let Some(next_ws) = next_ws { - let ws_text = next_ws.syntax().text(); - if let Some(rest) = ws_text.strip_prefix('\n') { - let next_use_removed = next_ws - .syntax() - .next_sibling_or_token() - .and_then(|it| it.into_node()) - .and_then(ast::Use::cast) - .and_then(|use_| use_.use_tree()) - .is_some_and(|use_tree| editor.deleted(use_tree.syntax())); - if rest.is_empty() || next_use_removed { - editor.delete(next_ws.syntax()); - } else { - editor.replace(next_ws.syntax(), make.whitespace(rest)); - } - } - } - let prev_ws = self - .syntax() - .prev_sibling_or_token() - .and_then(|it| it.into_token()) - .and_then(ast::Whitespace::cast); - if let Some(prev_ws) = prev_ws { - let ws_text = prev_ws.syntax().text(); - let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0); - let rest = &ws_text[0..prev_newline]; - if rest.is_empty() { - editor.delete(prev_ws.syntax()); - } else { - editor.replace(prev_ws.syntax(), make.whitespace(rest)); - } - } - - editor.delete(self.syntax()); - } -} - -impl ast::RecordExprField { - /// This will either replace the initializer, or in the case that this is a shorthand convert - /// the initializer into the name ref and insert the expr as the new initializer. - pub fn replace_expr(&self, editor: &SyntaxEditor, expr: ast::Expr) { - if self.name_ref().is_some() { - if let Some(prev) = self.expr() { - editor.replace(prev.syntax(), expr.syntax()); - } - } else if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() - && let Some(path) = path_expr.path() - && let Some(name_ref) = path.as_single_name_ref() - { - // shorthand `{ x }` → expand to `{ x: expr }` - let new_field = editor - .make() - .record_expr_field(editor.make().name_ref(&name_ref.text()), Some(expr)); - editor.replace(self.syntax(), new_field.syntax()); +impl ast::Impl { + pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList { + if self.assoc_item_list().is_none() { + let assoc_item_list = make::assoc_item_list(None).clone_for_update(); + ted::append_child(self.syntax(), assoc_item_list.syntax()); } + self.assoc_item_list().unwrap() } } From de273b809f56df77a9da3d84cda1aa56f51aaf26 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 May 2026 00:04:22 +0530 Subject: [PATCH 023/116] move all the editor variant of API's from edit-in-place to edit --- .../crates/syntax/src/ast/edit.rs | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index 2e3a4016ee89f..0155df8aa0b86 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -2,6 +2,7 @@ //! immutable, all function here return a fresh copy of the tree, instead of //! doing an in-place modification. use parser::T; +use rowan::Direction; use std::{ fmt, iter::{self, once}, @@ -12,6 +13,7 @@ use crate::{ AstToken, NodeOrToken, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, SyntaxNode, SyntaxToken, + algo::neighbor, ast::{self, AstNode, HasName, make}, syntax_editor::{Position, SyntaxEditor, SyntaxMappingBuilder}, }; @@ -263,6 +265,172 @@ pub fn indent(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode { level.clone_increase_indent(node) } +impl ast::GenericParamList { + /// Constructs a matching [`ast::GenericArgList`] + pub fn to_generic_args(&self, make: &SyntaxFactory) -> ast::GenericArgList { + let args = self.generic_params().filter_map(|param| match param { + ast::GenericParam::LifetimeParam(it) => { + Some(ast::GenericArg::LifetimeArg(make.lifetime_arg(it.lifetime()?))) + } + ast::GenericParam::TypeParam(it) => { + Some(ast::GenericArg::TypeArg(make.type_arg(make.ty_name(it.name()?)))) + } + ast::GenericParam::ConstParam(it) => { + // Name-only const params get parsed as `TypeArg`s + Some(ast::GenericArg::TypeArg(make.type_arg(make.ty_name(it.name()?)))) + } + }); + + make::generic_arg_list(args) + } +} + +impl ast::UseTree { + /// Editor variant of UseTree remove + fn remove_with_editor(&self, editor: &SyntaxEditor) { + for dir in [Direction::Next, Direction::Prev] { + if let Some(next_use_tree) = neighbor(self, dir) { + let separators = self + .syntax() + .siblings_with_tokens(dir) + .skip(1) + .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); + for separator in separators { + editor.delete(separator); + } + break; + } + } + editor.delete(self.syntax()); + } + + /// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty. + pub fn remove_recursive(self, editor: &SyntaxEditor) { + let parent = self.syntax().parent(); + + if let Some(u) = parent.clone().and_then(ast::Use::cast) { + u.remove(editor); + } else if let Some(u) = parent.and_then(ast::UseTreeList::cast) { + if u.use_trees().nth(1).is_none() + || u.use_trees().all(|use_tree| { + use_tree.syntax() == self.syntax() || editor.deleted(use_tree.syntax()) + }) + { + u.parent_use_tree().remove_recursive(editor); + return; + } + self.remove_with_editor(editor); + u.remove_unnecessary_braces(editor); + } + } + + /// Splits off the given prefix, making it the path component of the use tree, + /// appending the rest of the path to all UseTreeList items. + /// + /// # Examples + /// + /// `prefix$0::suffix` -> `prefix::{suffix}` + /// + /// `prefix$0` -> `prefix::{self}` + /// + /// `prefix$0::*` -> `prefix::{*}```` + pub fn split_prefix_with_editor(&self, editor: &SyntaxEditor, prefix: &ast::Path) { + debug_assert_eq!(self.path(), Some(prefix.top_path())); + + let make = editor.make(); + let path = self.path().unwrap(); + let suffix = if path == *prefix { + if self.use_tree_list().is_some() { + return; + } else if self.star_token().is_some() { + make.use_tree_glob() + } else { + let self_path = make.path_unqualified(make.path_segment_self()); + make.use_tree(self_path, None, self.rename(), false) + } + } else { + let suffix_segments = path.segments().skip(prefix.segments().count()); + let suffix_path = make.path_from_segments(suffix_segments, false); + make.use_tree( + suffix_path, + self.use_tree_list(), + self.rename(), + self.star_token().is_some(), + ) + }; + let use_tree_list = make.use_tree_list(once(suffix)); + let new_use_tree = make.use_tree(prefix.clone(), Some(use_tree_list), None, false); + + editor.replace(self.syntax(), new_use_tree.syntax()); + } +} + +impl ast::Use { + fn remove(&self, editor: &SyntaxEditor) { + let make = editor.make(); + let next_ws = self + .syntax() + .next_sibling_or_token() + .and_then(|it| it.into_token()) + .and_then(ast::Whitespace::cast); + if let Some(next_ws) = next_ws { + let ws_text = next_ws.syntax().text(); + if let Some(rest) = ws_text.strip_prefix('\n') { + let next_use_removed = next_ws + .syntax() + .next_sibling_or_token() + .and_then(|it| it.into_node()) + .and_then(ast::Use::cast) + .and_then(|use_| use_.use_tree()) + .is_some_and(|use_tree| editor.deleted(use_tree.syntax())); + if rest.is_empty() || next_use_removed { + editor.delete(next_ws.syntax()); + } else { + editor.replace(next_ws.syntax(), make.whitespace(rest)); + } + } + } + let prev_ws = self + .syntax() + .prev_sibling_or_token() + .and_then(|it| it.into_token()) + .and_then(ast::Whitespace::cast); + if let Some(prev_ws) = prev_ws { + let ws_text = prev_ws.syntax().text(); + let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0); + let rest = &ws_text[0..prev_newline]; + if rest.is_empty() { + editor.delete(prev_ws.syntax()); + } else { + editor.replace(prev_ws.syntax(), make.whitespace(rest)); + } + } + + editor.delete(self.syntax()); + } +} + +impl ast::RecordExprField { + /// This will either replace the initializer, or in the case that this is a shorthand convert + /// the initializer into the name ref and insert the expr as the new initializer. + pub fn replace_expr(&self, editor: &SyntaxEditor, expr: ast::Expr) { + if self.name_ref().is_some() { + if let Some(prev) = self.expr() { + editor.replace(prev.syntax(), expr.syntax()); + } + } else if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() + && let Some(path) = path_expr.path() + && let Some(name_ref) = path.as_single_name_ref() + { + // shorthand `{ x }` → expand to `{ x: expr }` + let new_field = editor + .make() + .record_expr_field(editor.make().name_ref(&name_ref.text()), Some(expr)); + editor.replace(self.syntax(), new_field.syntax()); + } + } +} + #[test] fn test_increase_indent() { let arm_list = { From 90fe5efb272393b1ce2cef1cf91637f2b2513036 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 May 2026 00:04:51 +0530 Subject: [PATCH 024/116] update test to use editor variant of try_merge_imports --- .../crates/ide-db/src/imports/insert_use/tests.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 4fa05c4603461..33db7178d6510 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -1430,7 +1430,8 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior .find_map(ast::Use::cast) .unwrap(); - let result = try_merge_imports(&use0, &use1, mb); + let editor = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()).0; + let result = try_merge_imports(&editor, &use0, &use1, mb); assert_eq!(result.map(|u| u.to_string()), None); } @@ -1495,7 +1496,8 @@ fn check_merge(ra_fixture0: &str, ra_fixture1: &str, last: &str, mb: MergeBehavi .find_map(ast::Use::cast) .unwrap(); - let result = try_merge_imports(&use0, &use1, mb); + let editor = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()).0; + let result = try_merge_imports(&editor, &use0, &use1, mb); assert_eq!(result.map(|u| u.to_string().trim().to_owned()), Some(last.trim().to_owned())); } @@ -1525,7 +1527,8 @@ fn merge_gated_imports_with_different_values() { .find_map(ast::Use::cast) .unwrap(); - let result = try_merge_imports(&use0, &use1, MergeBehavior::Crate); + let editor = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()).0; + let result = try_merge_imports(&editor, &use0, &use1, MergeBehavior::Crate); assert_eq!(result, None); } From e248498127922d76c4ddaf65efc3004ce0b4e454 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 May 2026 00:05:39 +0530 Subject: [PATCH 025/116] update insert_use to use editor variant of merge_import methods --- .../rust-analyzer/crates/ide-db/src/imports/insert_use.rs | 6 +++--- .../crates/ide-db/src/imports/insert_use/tests.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index c3949f871314f..1fd493fd2a730 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -17,7 +17,7 @@ use crate::{ RootDatabase, imports::merge_imports::{ MergeBehavior, NormalizationStyle, common_prefix, eq_attrs, eq_visibility, - try_merge_imports, use_tree_cmp, + try_merge_imports, use_tree_cmp, wrap_in_tree_list, }, }; @@ -251,7 +251,7 @@ fn insert_use_with_alias_option_with_editor( let mut use_tree = make.use_tree(path, None, alias, false); if mb == Some(MergeBehavior::One) && use_tree.path().is_some() - && let Some(wrapped) = use_tree.wrap_in_tree_list_with_editor() + && let Some(wrapped) = wrap_in_tree_list(&use_tree, make) { use_tree = wrapped; } @@ -263,7 +263,7 @@ fn insert_use_with_alias_option_with_editor( for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter) { - if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { + if let Some(merged) = try_merge_imports(syntax_editor, &existing_use, &use_item, mb) { syntax_editor.replace(existing_use.syntax(), merged.syntax()); return; } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 33db7178d6510..a30d290490210 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -1430,7 +1430,7 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior .find_map(ast::Use::cast) .unwrap(); - let editor = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()).0; + let (editor, _) = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()); let result = try_merge_imports(&editor, &use0, &use1, mb); assert_eq!(result.map(|u| u.to_string()), None); } @@ -1496,7 +1496,7 @@ fn check_merge(ra_fixture0: &str, ra_fixture1: &str, last: &str, mb: MergeBehavi .find_map(ast::Use::cast) .unwrap(); - let editor = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()).0; + let (editor, _) = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()); let result = try_merge_imports(&editor, &use0, &use1, mb); assert_eq!(result.map(|u| u.to_string().trim().to_owned()), Some(last.trim().to_owned())); } @@ -1527,7 +1527,7 @@ fn merge_gated_imports_with_different_values() { .find_map(ast::Use::cast) .unwrap(); - let editor = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()).0; + let (editor, _) = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()); let result = try_merge_imports(&editor, &use0, &use1, MergeBehavior::Crate); assert_eq!(result, None); } From 138846da0dee94c509fb8d5785271a8b734afaa8 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 May 2026 00:06:09 +0530 Subject: [PATCH 026/116] update normalize_import to use editor variant of merge_import methods --- .../crates/ide-assists/src/handlers/normalize_import.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs index f97a3e583f030..07571d74d8b8d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs @@ -1,5 +1,5 @@ use ide_db::imports::merge_imports::try_normalize_import; -use syntax::{AstNode, ast}; +use syntax::{AstNode, ast, syntax_editor::SyntaxEditor}; use crate::{ AssistId, @@ -25,11 +25,13 @@ pub(crate) fn normalize_import(acc: &mut Assists, ctx: &AssistContext<'_, '_>) - }; let target = use_item.syntax().text_range(); + let (editor, _) = SyntaxEditor::new(use_item.syntax().ancestors().last().unwrap()); let normalized_use_item = - try_normalize_import(&use_item, ctx.config.insert_use.granularity.into())?; + try_normalize_import(&editor, &use_item, ctx.config.insert_use.granularity.into())?; + editor.replace(use_item.syntax(), normalized_use_item.syntax()); acc.add(AssistId::refactor_rewrite("normalize_import"), "Normalize import", target, |builder| { - builder.replace_ast(use_item, normalized_use_item); + builder.add_file_edits(ctx.vfs_file_id(), editor); }) } From 7a7e02589e4081cd816f944c0942e7c3b2cf8104 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 May 2026 00:08:13 +0530 Subject: [PATCH 027/116] update merge_import to use editor variant of merge_import methods --- .../ide-assists/src/handlers/merge_imports.rs | 139 ++++++++---------- 1 file changed, 58 insertions(+), 81 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index dc40a6a640e00..e942be33d94c5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -1,10 +1,12 @@ -use either::Either; use ide_db::imports::{ insert_use::{ImportGranularity, InsertUseConfig}, merge_imports::{MergeBehavior, try_merge_imports, try_merge_trees}, }; use syntax::{ - AstNode, SyntaxElement, SyntaxNode, algo::neighbor, ast, match_ast, syntax_editor::Removable, + AstNode, SyntaxElement, + algo::neighbor, + ast, match_ast, + syntax_editor::{Removable, SyntaxEditor}, }; use crate::{ @@ -13,8 +15,6 @@ use crate::{ utils::next_prev, }; -use Edit::*; - // Assist: merge_imports // // Merges neighbor imports with a common prefix. @@ -28,16 +28,17 @@ use Edit::*; // use std::{fmt::Formatter, io}; // ``` pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> { - let (target, edits) = if ctx.has_empty_selection() { + let (target, editor) = if ctx.has_empty_selection() { // Merge a neighbor cov_mark::hit!(merge_with_use_item_neighbors); let tree = ctx.find_node_at_offset::()?.top_use_tree(); let target = tree.syntax().text_range(); let use_item = tree.syntax().parent().and_then(ast::Use::cast)?; - let mut neighbor = next_prev().find_map(|dir| neighbor(&use_item, dir)).into_iter(); - let edits = use_item.try_merge_from(&mut neighbor, &ctx.config.insert_use); - (target, edits?) + let neighbor = next_prev().find_map(|dir| neighbor(&use_item, dir))?; + let (editor, _) = SyntaxEditor::new(use_item.syntax().parent()?.ancestors().last()?); + merge_uses(use_item, vec![neighbor], &ctx.config.insert_use, &editor)?; + (target, editor) } else { // Merge selected let selection_range = ctx.selection_trimmed(); @@ -50,104 +51,80 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> O }); let first_selected = selected_nodes.next()?; - let edits = match_ast! { + let (editor, _) = SyntaxEditor::new(parent_node.ancestors().last().unwrap()); + match_ast! { match first_selected { ast::Use(use_item) => { cov_mark::hit!(merge_with_selected_use_item_neighbors); - use_item.try_merge_from(&mut selected_nodes.filter_map(ast::Use::cast), &ctx.config.insert_use) + merge_uses( + use_item, + selected_nodes.filter_map(ast::Use::cast).collect(), + &ctx.config.insert_use, + &editor, + )?; }, ast::UseTree(use_tree) => { cov_mark::hit!(merge_with_selected_use_tree_neighbors); - use_tree.try_merge_from(&mut selected_nodes.filter_map(ast::UseTree::cast), &ctx.config.insert_use) + merge_use_trees( + use_tree, + selected_nodes.filter_map(ast::UseTree::cast).collect(), + &editor, + )?; }, _ => return None, } - }; - (selection_range, edits?) - }; - - let parent_node = match ctx.covering_element() { - SyntaxElement::Node(n) => n, - SyntaxElement::Token(t) => t.parent()?, + } + (selection_range, editor) }; acc.add(AssistId::refactor_rewrite("merge_imports"), "Merge imports", target, |builder| { - let editor = builder.make_editor(&parent_node); - - for edit in edits { - match edit { - Remove(it) => { - let node = it.as_ref(); - if let Some(left) = node.left() { - left.remove(&editor); - } else if let Some(right) = node.right() { - right.remove(&editor); - } - } - Replace(old, new) => { - editor.replace(old, &new); - } - } - } builder.add_file_edits(ctx.vfs_file_id(), editor); }) } -trait Merge: AstNode + Clone { - fn try_merge_from( - self, - items: &mut dyn Iterator, - cfg: &InsertUseConfig, - ) -> Option> { - let mut edits = Vec::new(); - let mut merged = self.clone(); - for item in items { - merged = merged.try_merge(&item, cfg)?; - edits.push(Edit::Remove(item.into_either())); - } - if !edits.is_empty() { - edits.push(Edit::replace(self, merged)); - Some(edits) - } else { - None - } +fn merge_uses( + first: ast::Use, + rest: Vec, + cfg: &InsertUseConfig, + editor: &SyntaxEditor, +) -> Option<()> { + if rest.is_empty() { + return None; } - fn try_merge(&self, other: &Self, cfg: &InsertUseConfig) -> Option; - fn into_either(self) -> Either; -} -impl Merge for ast::Use { - fn try_merge(&self, other: &Self, cfg: &InsertUseConfig) -> Option { - let mb = match cfg.granularity { - ImportGranularity::One => MergeBehavior::One, - _ => MergeBehavior::Crate, - }; - try_merge_imports(self, other, mb) + let mb = match cfg.granularity { + ImportGranularity::One => MergeBehavior::One, + _ => MergeBehavior::Crate, + }; + let mut merged = first.clone(); + for item in &rest { + merged = try_merge_imports(editor, &merged, item, mb)?; } - fn into_either(self) -> Either { - Either::Left(self) + for item in rest { + item.remove(editor); } + editor.replace(first.syntax(), merged.syntax()); + Some(()) } -impl Merge for ast::UseTree { - fn try_merge(&self, other: &Self, _: &InsertUseConfig) -> Option { - try_merge_trees(self, other, MergeBehavior::Crate) - } - fn into_either(self) -> Either { - Either::Right(self) +fn merge_use_trees( + first: ast::UseTree, + rest: Vec, + editor: &SyntaxEditor, +) -> Option<()> { + if rest.is_empty() { + return None; } -} - -#[derive(Debug)] -enum Edit { - Remove(Either), - Replace(SyntaxNode, SyntaxNode), -} -impl Edit { - fn replace(old: impl AstNode, new: impl AstNode) -> Self { - Edit::Replace(old.syntax().clone(), new.syntax().clone()) + let mut merged = first.clone(); + for item in &rest { + merged = try_merge_trees(editor, &merged, item, MergeBehavior::Crate)?; + } + for item in rest { + item.remove(editor); } + editor.replace(first.syntax(), merged.syntax()); + Some(()) } #[cfg(test)] From bf226d8cfd2fec2da50e37f52e30a8bbe047f0ae Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 25 May 2026 23:02:14 +0530 Subject: [PATCH 028/116] migrate merge_import to syntax_editor --- .../ide-db/src/imports/merge_imports.rs | 673 +++++++++++------- 1 file changed, 405 insertions(+), 268 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index bbd351a4cc14c..95e654df174f5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -4,12 +4,12 @@ use std::cmp::Ordering; use itertools::{EitherOrBoth, Itertools}; use parser::T; use syntax::{ - Direction, SyntaxElement, ToSmolStr, algo, + ToSmolStr, ast::{ - self, AstNode, HasAttrs, HasName, HasVisibility, PathSegmentKind, edit_in_place::Removable, - make, + self, AstNode, HasAttrs, HasName, HasVisibility, PathSegmentKind, + syntax_factory::SyntaxFactory, }, - ted::{self, Position}, + syntax_editor::{Position, SyntaxEditor}, }; use crate::syntax_helpers::node_ext::vis_eq; @@ -39,8 +39,8 @@ impl MergeBehavior { } /// Merge `rhs` into `lhs` keeping both intact. -/// Returned AST is mutable. pub fn try_merge_imports( + editor: &SyntaxEditor, lhs: &ast::Use, rhs: &ast::Use, merge_behavior: MergeBehavior, @@ -53,39 +53,41 @@ pub fn try_merge_imports( return None; } - let lhs = lhs.clone_subtree().clone_for_update(); - let rhs = rhs.clone_subtree().clone_for_update(); + let make = editor.make(); let lhs_tree = lhs.use_tree()?; let rhs_tree = rhs.use_tree()?; - try_merge_trees_mut(&lhs_tree, &rhs_tree, merge_behavior)?; + let merged_tree = try_merge_trees_with_factory(lhs_tree, rhs_tree, merge_behavior, make)?; // Ignore `None` result because normalization should not affect the merge result. - try_normalize_use_tree_mut(&lhs_tree, merge_behavior.into()); + let use_tree = try_normalize_use_tree(merged_tree.clone(), merge_behavior.into(), make) + .unwrap_or(merged_tree); - Some(lhs) + make_use_with_tree(lhs, use_tree) } /// Merge `rhs` into `lhs` keeping both intact. -/// Returned AST is mutable. pub fn try_merge_trees( + editor: &SyntaxEditor, lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior, ) -> Option { - let lhs = lhs.clone_subtree().clone_for_update(); - let rhs = rhs.clone_subtree().clone_for_update(); - try_merge_trees_mut(&lhs, &rhs, merge)?; + let make = editor.make(); + let merged = try_merge_trees_with_factory(lhs.clone(), rhs.clone(), merge, make)?; // Ignore `None` result because normalization should not affect the merge result. - try_normalize_use_tree_mut(&lhs, merge.into()); - - Some(lhs) + Some(try_normalize_use_tree(merged.clone(), merge.into(), make).unwrap_or(merged)) } -fn try_merge_trees_mut(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> { +fn try_merge_trees_with_factory( + mut lhs: ast::UseTree, + mut rhs: ast::UseTree, + merge: MergeBehavior, + make: &SyntaxFactory, +) -> Option { if merge == MergeBehavior::One { - lhs.wrap_in_tree_list(); - rhs.wrap_in_tree_list(); + lhs = wrap_in_tree_list(&lhs, make).unwrap_or(lhs); + rhs = wrap_in_tree_list(&rhs, make).unwrap_or(rhs); } else { let lhs_path = lhs.path()?; let rhs_path = rhs.path()?; @@ -98,48 +100,59 @@ fn try_merge_trees_mut(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehav { // we can't merge if the renames are different (`A as a` and `A as b`), // and we can safely return here - let lhs_name = lhs.rename().and_then(|lhs_name| lhs_name.name()); - let rhs_name = rhs.rename().and_then(|rhs_name| rhs_name.name()); + let lhs_name = lhs + .rename() + .and_then(|lhs_name| lhs_name.name()) + .map(|name| name.text().to_string()); + let rhs_name = rhs + .rename() + .and_then(|rhs_name| rhs_name.name()) + .map(|name| name.text().to_string()); if lhs_name != rhs_name { return None; } - ted::replace(lhs.syntax(), rhs.syntax()); - // we can safely return here, in this case `recursive_merge` doesn't do anything - return Some(()); + return Some(rhs); } else { - lhs.split_prefix(&lhs_prefix); - rhs.split_prefix(&rhs_prefix); + lhs = split_prefix(&lhs, &lhs_prefix, make)?; + rhs = split_prefix(&rhs, &rhs_prefix, make)?; } } - recursive_merge(lhs, rhs, merge) + recursive_merge(lhs, rhs, merge, make) } /// Recursively merges rhs to lhs #[must_use] -fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> { +fn recursive_merge( + lhs: ast::UseTree, + rhs: ast::UseTree, + merge: MergeBehavior, + make: &SyntaxFactory, +) -> Option { let mut use_trees: Vec = lhs - .use_tree_list() - .into_iter() - .flat_map(|list| list.use_trees()) - // We use Option here to early return from this function(this is not the - // same as a `filter` op). + .use_tree_list()? + .use_trees() + // We use Option here to early return from this function. This is not the + // same as a `filter` op. .map(|tree| merge.is_tree_allowed(&tree).then_some(tree)) .collect::>()?; + // Sorts the use trees similar to rustfmt's algorithm for ordering imports // (see `use_tree_cmp` doc). use_trees.sort_unstable_by(use_tree_cmp); - for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) { + + for rhs_t in rhs.use_tree_list()?.use_trees() { if !merge.is_tree_allowed(&rhs_t) { return None; } match use_trees.binary_search_by(|lhs_t| use_tree_cmp_bin_search(lhs_t, &rhs_t)) { Ok(idx) => { - let lhs_t = &mut use_trees[idx]; + let mut lhs_t = use_trees[idx].clone(); let lhs_path = lhs_t.path()?; let rhs_path = rhs_t.path()?; let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; + if lhs_prefix == lhs_path && rhs_prefix == rhs_path { let tree_is_self = |tree: &ast::UseTree| { tree.path().as_ref().map(path_is_self).unwrap_or(false) @@ -157,20 +170,20 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) }; if lhs_t.rename().and_then(|x| x.underscore_token()).is_some() { - ted::replace(lhs_t.syntax(), rhs_t.syntax()); - *lhs_t = rhs_t; + use_trees[idx] = rhs_t; continue; } - match (tree_contains_self(lhs_t), tree_contains_self(&rhs_t)) { + match (tree_contains_self(&lhs_t), tree_contains_self(&rhs_t)) { (Some(true), None) => { - remove_subtree_if_only_self(lhs_t); + lhs_t = remove_subtree_if_only_self(lhs_t, make)?; + use_trees[idx] = lhs_t; continue; } (None, Some(true)) => { - ted::replace(lhs_t.syntax(), rhs_t.syntax()); - *lhs_t = rhs_t; - remove_subtree_if_only_self(lhs_t); + lhs_t = rhs_t; + lhs_t = remove_subtree_if_only_self(lhs_t, make)?; + use_trees[idx] = lhs_t; continue; } _ => (), @@ -180,9 +193,11 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) continue; } } - lhs_t.split_prefix(&lhs_prefix); - rhs_t.split_prefix(&rhs_prefix); - recursive_merge(lhs_t, &rhs_t, merge)?; + + lhs_t = split_prefix(&lhs_t, &lhs_prefix, make)?; + let rhs_t = split_prefix(&rhs_t, &rhs_prefix, make)?; + lhs_t = recursive_merge(lhs_t, rhs_t, merge, make)?; + use_trees[idx] = lhs_t; } Err(_) if merge == MergeBehavior::Module @@ -192,15 +207,12 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) return None; } Err(insert_idx) => { - use_trees.insert(insert_idx, rhs_t.clone()); - // We simply add the use tree to the end of tree list. Ordering of use trees - // and imports is done by the `try_normalize_*` functions. The sorted `use_trees` - // vec is only used for binary search. - lhs.get_or_create_use_tree_list().add_use_tree(rhs_t); + use_trees.insert(insert_idx, rhs_t); } } } - Some(()) + + with_use_tree_list(&lhs, use_trees, make) } /// Style to follow when normalizing a use tree. @@ -250,241 +262,217 @@ impl From for NormalizationStyle { /// - `foo::{bar::Qux, bar::{self}}` -> `{foo::bar::{self, Qux}}` /// - `foo::bar::{self}` -> `{foo::bar}` /// - `foo::bar` -> `{foo::bar}` -pub fn try_normalize_import(use_item: &ast::Use, style: NormalizationStyle) -> Option { - let use_item = use_item.clone_subtree().clone_for_update(); - try_normalize_use_tree_mut(&use_item.use_tree()?, style)?; - Some(use_item) +pub fn try_normalize_import( + editor: &SyntaxEditor, + use_item: &ast::Use, + style: NormalizationStyle, +) -> Option { + let make = editor.make(); + let use_tree = try_normalize_use_tree(use_item.use_tree()?, style, make)?; + + make_use_with_tree(use_item, use_tree) } -fn try_normalize_use_tree_mut(use_tree: &ast::UseTree, style: NormalizationStyle) -> Option<()> { +fn try_normalize_use_tree( + use_tree: ast::UseTree, + style: NormalizationStyle, + make: &SyntaxFactory, +) -> Option { if style == NormalizationStyle::One { + let mut use_tree = use_tree; let mut modified = false; - modified |= use_tree.wrap_in_tree_list().is_some(); - modified |= recursive_normalize(use_tree, style).is_some(); - if !modified { - // Either the use tree was already normalized or its semantically empty. - return None; + if let Some(wrapped) = wrap_in_tree_list(&use_tree, make) { + use_tree = wrapped; + modified = true; } - } else { - recursive_normalize(use_tree, NormalizationStyle::Default)?; + if let Some(normalized) = recursive_normalize(use_tree.clone(), style, make) { + use_tree = normalized; + modified = true; + } + return modified.then_some(use_tree); } - Some(()) + + recursive_normalize(use_tree, NormalizationStyle::Default, make) } /// Recursively normalizes a use tree and its subtrees (if any). -fn recursive_normalize(use_tree: &ast::UseTree, style: NormalizationStyle) -> Option<()> { +fn recursive_normalize( + use_tree: ast::UseTree, + style: NormalizationStyle, + make: &SyntaxFactory, +) -> Option { let use_tree_list = use_tree.use_tree_list()?; - let merge_subtree_into_parent_tree = |single_subtree: &ast::UseTree| { - let subtree_is_only_self = single_subtree.path().as_ref().is_some_and(path_is_self); - - let merged_path = match (use_tree.path(), single_subtree.path()) { - // If the subtree is `{self}` then we cannot merge: `use - // foo::bar::{self}` is not equivalent to `use foo::bar`. See - // https://github.com/rust-lang/rust-analyzer/pull/17140#issuecomment-2079189725. - _ if subtree_is_only_self => None, - - (None, None) => None, - (Some(outer), None) => Some(outer), - (None, Some(inner)) => Some(inner), - (Some(outer), Some(inner)) => Some(make::path_concat(outer, inner).clone_for_update()), - }; - - if merged_path.is_some() - || single_subtree.use_tree_list().is_some() - || single_subtree.star_token().is_some() + let mut subtrees = use_tree_list.use_trees().collect::>(); + if subtrees.len() == 1 { + if style == NormalizationStyle::One { + let subtree = subtrees.pop()?; + let normalized = recursive_normalize(subtree, NormalizationStyle::Default, make)?; + return with_use_tree_list(&use_tree, vec![normalized], make); + } + + let merged = merge_single_subtree_into_parent_tree(use_tree, make)?; + return Some(recursive_normalize(merged.clone(), style, make).unwrap_or(merged)); + } + + let mut modified = false; + let mut new_use_tree_list = Vec::new(); + for subtree in subtrees { + if one_style_tree_list(&subtree).is_some() { + let mut elements = Vec::new(); + flatten_one_style_tree(subtree, &mut elements, &mut modified, make); + new_use_tree_list.extend(elements); + modified = true; + } else if let Some(normalized) = + recursive_normalize(subtree.clone(), NormalizationStyle::Default, make) { - ted::remove_all_iter(use_tree.syntax().children_with_tokens()); - if let Some(path) = merged_path { - ted::insert_raw(Position::first_child_of(use_tree.syntax()), path.syntax()); - if single_subtree.use_tree_list().is_some() || single_subtree.star_token().is_some() + new_use_tree_list.push(normalized); + modified = true; + } else { + new_use_tree_list.push(subtree); + } + } + + let mut use_tree = + if modified { with_use_tree_list(&use_tree, new_use_tree_list, make)? } else { use_tree }; + + let mut use_tree_list = use_tree.use_tree_list()?.use_trees().collect::>(); + let mut anchor_idx = 0; + let mut merged_any = false; + while anchor_idx < use_tree_list.len() { + let mut candidate_idx = anchor_idx + 1; + while candidate_idx < use_tree_list.len() { + if let Some(mut merged) = try_merge_trees_with_factory( + use_tree_list[anchor_idx].clone(), + use_tree_list[candidate_idx].clone(), + MergeBehavior::Crate, + make, + ) { + if let Some(normalized) = + recursive_normalize(merged.clone(), NormalizationStyle::Default, make) { - ted::insert_raw( - Position::last_child_of(use_tree.syntax()), - make::token(T![::]), - ); + merged = normalized; } + + use_tree_list[anchor_idx] = merged; + use_tree_list.remove(candidate_idx); + merged_any = true; + } else { + candidate_idx += 1; } - if let Some(inner_use_tree_list) = single_subtree.use_tree_list() { - ted::insert_raw( - Position::last_child_of(use_tree.syntax()), - inner_use_tree_list.syntax(), - ); - } else if single_subtree.star_token().is_some() { - ted::insert_raw(Position::last_child_of(use_tree.syntax()), make::token(T![*])); - } else if let Some(rename) = single_subtree.rename() { - ted::insert_raw( - Position::last_child_of(use_tree.syntax()), - make::tokens::single_space(), - ); - ted::insert_raw(Position::last_child_of(use_tree.syntax()), rename.syntax()); - } - Some(()) - } else { - // Bail on semantically empty use trees. - None } - }; - let one_style_tree_list = |subtree: &ast::UseTree| match ( - subtree.path().is_none() && subtree.star_token().is_none() && subtree.rename().is_none(), - subtree.use_tree_list(), - ) { - (true, tree_list) => tree_list, - _ => None, - }; - let add_element_to_list = |elem: SyntaxElement, elements: &mut Vec| { - if !elements.is_empty() { - elements.push(make::token(T![,]).into()); - elements.push(make::tokens::single_space().into()); + + anchor_idx += 1; + } + if merged_any { + use_tree = with_use_tree_list(&use_tree, use_tree_list, make)?; + modified = true; + } + + if style != NormalizationStyle::One { + let subtrees = use_tree.use_tree_list()?.use_trees().collect::>(); + if subtrees.len() == 1 + && let Some(merged) = merge_single_subtree_into_parent_tree(use_tree.clone(), make) + { + use_tree = merged; + modified = true; } - elements.push(elem); - }; - if let Some((single_subtree,)) = use_tree_list.use_trees().collect_tuple() { - if style == NormalizationStyle::One { - // Only normalize descendant subtrees if the normalization style is "one". - recursive_normalize(&single_subtree, NormalizationStyle::Default)?; - } else { - // Otherwise, merge the single subtree into it's parent (if possible) - // and then normalize the result. - merge_subtree_into_parent_tree(&single_subtree)?; - recursive_normalize(use_tree, style); + } + + if let Some(list) = use_tree.use_tree_list() { + let mut use_tree_list = list.use_trees().collect::>(); + if use_tree_list + .windows(2) + .any(|trees| use_tree_cmp_bin_search(&trees[0], &trees[1]).is_gt()) + { + use_tree_list.sort_unstable_by(use_tree_cmp_bin_search); + use_tree = with_use_tree_list(&use_tree, use_tree_list, make)?; + modified = true; } - } else { - // Tracks whether any changes have been made to the use tree. - let mut modified = false; + } - // Recursively un-nests (if necessary) and then normalizes each subtree in the tree list. - for subtree in use_tree_list.use_trees() { - if let Some(one_tree_list) = one_style_tree_list(&subtree) { - let mut elements = Vec::new(); - let mut one_tree_list_iter = one_tree_list.use_trees(); - let mut prev_skipped = Vec::new(); - loop { - let mut prev_skipped_iter = prev_skipped.into_iter(); - let mut curr_skipped = Vec::new(); - - while let Some(sub_sub_tree) = - one_tree_list_iter.next().or(prev_skipped_iter.next()) - { - if let Some(sub_one_tree_list) = one_style_tree_list(&sub_sub_tree) { - curr_skipped.extend(sub_one_tree_list.use_trees()); - } else { - modified |= - recursive_normalize(&sub_sub_tree, NormalizationStyle::Default) - .is_some(); - add_element_to_list( - sub_sub_tree.syntax().clone().into(), - &mut elements, - ); - } - } + modified.then_some(use_tree) +} - if curr_skipped.is_empty() { - // Un-nesting is complete. - break; - } - prev_skipped = curr_skipped; - } +fn flatten_one_style_tree( + subtree: ast::UseTree, + elements: &mut Vec, + modified: &mut bool, + make: &SyntaxFactory, +) { + let Some(one_tree_list) = one_style_tree_list(&subtree) else { return }; + let mut one_tree_list_iter = one_tree_list.use_trees(); + let mut prev_skipped = Vec::new(); + loop { + let mut prev_skipped_iter = prev_skipped.into_iter(); + let mut curr_skipped = Vec::new(); - // Either removes the subtree (if its semantically empty) or replaces it with - // the un-nested elements. - if elements.is_empty() { - subtree.remove(); - } else { - ted::replace_with_many(subtree.syntax(), elements); - } - // Silence unused assignment warning on `modified`. - let _ = modified; - modified = true; + while let Some(sub_sub_tree) = + one_tree_list_iter.next().or_else(|| prev_skipped_iter.next()) + { + if let Some(sub_one_tree_list) = one_style_tree_list(&sub_sub_tree) { + curr_skipped.extend(sub_one_tree_list.use_trees()); + } else if let Some(normalized) = + recursive_normalize(sub_sub_tree.clone(), NormalizationStyle::Default, make) + { + *modified = true; + elements.push(normalized); } else { - modified |= recursive_normalize(&subtree, NormalizationStyle::Default).is_some(); + elements.push(sub_sub_tree); } } - // Merge all merge-able subtrees. - let mut tree_list_iter = use_tree_list.use_trees(); - let mut anchor = tree_list_iter.next()?; - let mut prev_skipped = Vec::new(); - loop { - let mut has_merged = false; - let mut prev_skipped_iter = prev_skipped.into_iter(); - let mut next_anchor = None; - let mut curr_skipped = Vec::new(); - - while let Some(candidate) = tree_list_iter.next().or(prev_skipped_iter.next()) { - let result = try_merge_trees_mut(&anchor, &candidate, MergeBehavior::Crate); - if result.is_some() { - // Remove merged subtree. - candidate.remove(); - has_merged = true; - } else if next_anchor.is_none() { - next_anchor = Some(candidate); - } else { - curr_skipped.push(candidate); - } - } - - if has_merged { - // Normalize the merge result. - recursive_normalize(&anchor, NormalizationStyle::Default); - modified = true; - } + if curr_skipped.is_empty() { + break; + } + prev_skipped = curr_skipped; + } +} - let (Some(next_anchor), true) = (next_anchor, !curr_skipped.is_empty()) else { - // Merging is complete. - break; - }; +fn merge_single_subtree_into_parent_tree( + use_tree: ast::UseTree, + make: &SyntaxFactory, +) -> Option { + let single_subtree = get_single_subtree(&use_tree)?; + let subtree_is_only_self = single_subtree.path().as_ref().is_some_and(path_is_self); + + let merged_path = match (use_tree.path(), single_subtree.path()) { + _ if subtree_is_only_self => None, + (None, None) => None, + (Some(outer), None) => Some(outer), + (None, Some(inner)) => Some(inner), + (Some(outer), Some(inner)) => Some(make.path_concat(outer, inner)), + }; - // Try to merge the remaining subtrees in the next iteration. - anchor = next_anchor; - prev_skipped = curr_skipped; - } + let list = single_subtree.use_tree_list(); + let list_is_none = list.is_none(); + let star = single_subtree.star_token().is_some(); + if merged_path.is_some() || list.is_some() || star { + let rename = (!star && list_is_none).then(|| single_subtree.rename()).flatten(); + make_use_tree_from_parts(make, merged_path, list, rename, star) + } else { + None + } +} - let mut subtrees: Vec<_> = use_tree_list.use_trees().collect(); - // Merge the remaining subtree into its parent, if its only one and - // the normalization style is not "one". - if subtrees.len() == 1 && style != NormalizationStyle::One { - modified |= merge_subtree_into_parent_tree(&subtrees[0]).is_some(); - } - // Order the remaining subtrees (if necessary). - if subtrees.len() > 1 { - let mut did_sort = false; - subtrees.sort_unstable_by(|a, b| { - let order = use_tree_cmp_bin_search(a, b); - if !did_sort && order == Ordering::Less { - did_sort = true; - } - order - }); - if did_sort { - let start = use_tree_list - .l_curly_token() - .and_then(|l_curly| algo::non_trivia_sibling(l_curly.into(), Direction::Next)) - .filter(|it| it.kind() != T!['}']); - let end = use_tree_list - .r_curly_token() - .and_then(|r_curly| algo::non_trivia_sibling(r_curly.into(), Direction::Prev)) - .filter(|it| it.kind() != T!['{']); - if let Some((start, end)) = start.zip(end) { - // Attempt to insert elements while preserving preceding and trailing trivia. - let mut elements = Vec::new(); - for subtree in subtrees { - add_element_to_list(subtree.syntax().clone().into(), &mut elements); - } - ted::replace_all(start..=end, elements); - } else { - let new_use_tree_list = make::use_tree_list(subtrees).clone_for_update(); - ted::replace(use_tree_list.syntax(), new_use_tree_list.syntax()); - } - modified = true; - } - } +fn one_style_tree_list(subtree: &ast::UseTree) -> Option { + (subtree.path().is_none() && subtree.star_token().is_none() && subtree.rename().is_none()) + .then(|| subtree.use_tree_list()) + .flatten() +} - if !modified { - // Either the use tree was already normalized or its semantically empty. - return None; +fn remove_subtree_if_only_self( + use_tree: ast::UseTree, + make: &SyntaxFactory, +) -> Option { + let Some(single_subtree) = get_single_subtree(&use_tree) else { + return Some(use_tree); + }; + match (use_tree.path(), single_subtree.path()) { + (Some(path), Some(inner)) if path_is_self(&inner) => { + Some(make.use_tree(path, None, use_tree.rename(), false)) } + _ => Some(use_tree), } - Some(()) } /// Traverses both paths until they differ, returning the common prefix of both. @@ -513,10 +501,9 @@ pub fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast fn use_tree_cmp_bin_search(lhs: &ast::UseTree, rhs: &ast::UseTree) -> Ordering { let lhs_is_simple_path = lhs.is_simple_path() && lhs.rename().is_none(); let rhs_is_simple_path = rhs.is_simple_path() && rhs.rename().is_none(); - match ( - lhs.path().as_ref().and_then(ast::Path::first_segment), - rhs.path().as_ref().and_then(ast::Path::first_segment), - ) { + let lhs_segment = lhs.path().and_then(|path| path.first_segment()); + let rhs_segment = rhs.path().and_then(|path| path.first_segment()); + match (lhs_segment, rhs_segment) { (None, None) => match (lhs_is_simple_path, rhs_is_simple_path) { (true, true) => Ordering::Equal, (true, false) => Ordering::Less, @@ -701,14 +688,164 @@ fn get_single_subtree(use_tree: &ast::UseTree) -> Option { .map(|(single_subtree,)| single_subtree) } -fn remove_subtree_if_only_self(use_tree: &ast::UseTree) { - let Some(single_subtree) = get_single_subtree(use_tree) else { return }; - match (use_tree.path(), single_subtree.path()) { - (Some(_), Some(inner)) if path_is_self(&inner) => { - ted::remove_all_iter(single_subtree.syntax().children_with_tokens()); - } - _ => (), +fn make_use_with_tree(original: &ast::Use, use_tree: ast::UseTree) -> Option { + let (editor, use_item) = SyntaxEditor::with_ast_node(original); + let original_tree = use_item.use_tree()?; + editor.replace(original_tree.syntax(), use_tree.syntax()); + let edit = editor.finish(); + ast::Use::cast(edit.new_root().clone()) +} + +fn make_use_tree_list( + make: &SyntaxFactory, + use_trees: Vec, + style_source: Option<&ast::UseTreeList>, +) -> Option { + let use_tree_list = make.use_tree_list(use_trees); + let Some(style_source) = style_source else { + return Some(use_tree_list); + }; + + let source_l_curly = style_source.l_curly_token()?; + let source_r_curly = style_source.r_curly_token()?; + + let leading_ws = source_l_curly.next_token().filter(|token| token.kind().is_trivia()); + + let trailing_ws = source_r_curly.prev_token().filter(|token| token.kind().is_trivia()); + + let source_trailing_token = trailing_ws + .as_ref() + .and_then(|token| token.prev_token()) + .or_else(|| source_r_curly.prev_token()); + + let source_has_trailing_comma = + source_trailing_token.is_some_and(|token| token.kind() == T![,]); + + let (editor, use_tree_list) = SyntaxEditor::with_ast_node(&use_tree_list); + let make = editor.make(); + + if let Some(leading_ws) = leading_ws { + editor.insert( + Position::after(use_tree_list.l_curly_token()?), + make.whitespace(leading_ws.text()), + ); } + + let r_curly = use_tree_list.r_curly_token()?; + + let generated_has_trailing_comma = r_curly + .prev_token() + .and_then(|token| if token.kind().is_trivia() { token.prev_token() } else { Some(token) }) + .is_some_and(|token| token.kind() == T![,]); + + let mut trailing = Vec::new(); + + if source_has_trailing_comma + && !generated_has_trailing_comma + && use_tree_list.use_trees().next().is_some() + { + trailing.push(make.token(T![,]).into()); + } + + if let Some(trailing_ws) = trailing_ws { + trailing.push(make.whitespace(trailing_ws.text()).into()); + } + + if !trailing.is_empty() { + editor.insert_all(Position::before(r_curly), trailing); + } + + let edit = editor.finish(); + ast::UseTreeList::cast(edit.new_root().clone()) +} + +fn make_use_tree_from_list(make: &SyntaxFactory, list: ast::UseTreeList) -> Option { + let placeholder = make.use_tree_glob(); + let (editor, use_tree) = SyntaxEditor::with_ast_node(&placeholder); + let first_child = use_tree.syntax().first_child_or_token()?; + let last_child = use_tree.syntax().last_child_or_token()?; + editor.replace_all(first_child..=last_child, vec![list.syntax().clone().into()]); + let edit = editor.finish(); + ast::UseTree::cast(edit.new_root().clone()) +} + +fn make_use_tree_from_parts( + make: &SyntaxFactory, + path: Option, + list: Option, + rename: Option, + star: bool, +) -> Option { + match (path, list, star) { + (Some(path), list, star) => Some(make.use_tree(path, list, rename, star)), + (None, Some(list), false) if rename.is_none() => make_use_tree_from_list(make, list), + (None, None, true) if rename.is_none() => Some(make.use_tree_glob()), + (None, None, false) if rename.is_none() => None, + _ => None, + } +} + +fn with_use_tree_list( + use_tree: &ast::UseTree, + use_trees: Vec, + make: &SyntaxFactory, +) -> Option { + let list = make_use_tree_list(make, use_trees, use_tree.use_tree_list().as_ref())?; + make_use_tree_from_parts( + make, + use_tree.path(), + Some(list), + use_tree.rename(), + use_tree.star_token().is_some(), + ) +} + +pub(crate) fn wrap_in_tree_list( + use_tree: &ast::UseTree, + make: &SyntaxFactory, +) -> Option { + if use_tree.path().is_none() + && use_tree.use_tree_list().is_some() + && use_tree.rename().is_none() + && use_tree.star_token().is_none() + { + return None; + } + + let list = make_use_tree_list(make, vec![use_tree.clone()], None)?; + make_use_tree_from_list(make, list) +} + +fn split_prefix( + use_tree: &ast::UseTree, + prefix: &ast::Path, + make: &SyntaxFactory, +) -> Option { + let path = use_tree.path()?; + if path == *prefix && use_tree.use_tree_list().is_some() { + return Some(use_tree.clone()); + } + + let suffix = if path == *prefix { + if use_tree.star_token().is_some() { + make.use_tree_glob() + } else { + let self_path = make.path_unqualified(make.path_segment_self()); + make.use_tree(self_path, None, use_tree.rename(), false) + } + } else { + let suffix_segments = path.segments().skip(prefix.segments().count()); + let suffix_path = make.path_from_segments(suffix_segments, false); + make.use_tree( + suffix_path, + use_tree.use_tree_list(), + use_tree.rename(), + use_tree.star_token().is_some(), + ) + }; + + let list = make_use_tree_list(make, vec![suffix], None)?; + Some(make.use_tree(prefix.clone(), Some(list), None, false)) } // Taken from rustfmt From 368efc5755c25d792b35478124ce7577389d37fb Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 12 Jun 2026 15:06:34 +0530 Subject: [PATCH 029/116] Remove edit in place --- src/tools/rust-analyzer/crates/syntax/src/ast.rs | 1 - .../crates/syntax/src/ast/edit_in_place.rs | 16 ---------------- 2 files changed, 17 deletions(-) delete mode 100644 src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs index dc592a43727b4..d8c7e1583031d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs @@ -1,7 +1,6 @@ //! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s pub mod edit; -pub mod edit_in_place; mod expr_ext; mod generated; pub mod make; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs deleted file mode 100644 index 4a38cb8198e3f..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Structural editing for ast. -use crate::{ - AstNode, - ast::{self, make}, - ted, -}; - -impl ast::Impl { - pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList { - if self.assoc_item_list().is_none() { - let assoc_item_list = make::assoc_item_list(None).clone_for_update(); - ted::append_child(self.syntax(), assoc_item_list.syntax()); - } - self.assoc_item_list().unwrap() - } -} From 39b7e48eba51f7af03734a885e29bd36abd33ead Mon Sep 17 00:00:00 2001 From: "chad@gazdeb" Date: Fri, 12 Jun 2026 06:58:46 -0400 Subject: [PATCH 030/116] Remove unnecessary feature flags from tests The `bindings_after_at`, `if_let_guard`, and `trait_upcasting` features are stable, so the tests for these features no longer require enabling them. --- .../ide-assists/src/handlers/destructure_tuple_binding.rs | 4 ---- .../ide-assists/src/handlers/replace_if_let_with_match.rs | 6 ------ .../crates/ide-diagnostics/src/handlers/invalid_cast.rs | 1 - 3 files changed, 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 2755962362677..a272351e134cc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -1236,15 +1236,11 @@ fn main { fn destructure_in_sub_pattern() { check_sub_pattern_assist( r#" -#![feature(bindings_after_at)] - fn main() { let $0t = (1,2); } "#, r#" -#![feature(bindings_after_at)] - fn main() { let t @ ($0_0, _1) = (1,2); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index ff2d0544b2a18..6959988db7f03 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -712,13 +712,11 @@ impl VariantData { check_assist( replace_if_let_with_match, r#" -#![feature(if_let_guard)] fn main() { if $0let true = true && let Some(1) = None {} else { other() } } "#, r#" -#![feature(if_let_guard)] fn main() { match true { true if let Some(1) = None => {} @@ -731,7 +729,6 @@ fn main() { check_assist( replace_if_let_with_match, r#" -#![feature(if_let_guard)] fn main() { if true { $0if let ParenExpr(expr) = cond @@ -758,7 +755,6 @@ fn main() { } "#, r#" -#![feature(if_let_guard)] fn main() { if true { match cond { @@ -816,13 +812,11 @@ fn main() { check_assist( replace_if_let_with_match, r#" -#![feature(if_let_guard)] fn main() { if $0let true = true && let Some(1) = None {} } "#, r#" -#![feature(if_let_guard)] fn main() { match true { true if let Some(1) = None => {} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs index bd8fa69e28707..e1c2053289b96 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -1025,7 +1025,6 @@ fn _slice(bar: &[i32]) -> bool { check_diagnostics( r#" //- minicore: coerce_unsized, dispatch_from_dyn -#![feature(trait_upcasting)] trait Foo {} trait Bar: Foo {} From 3bfb4225f1b69a0ce9260b952aa1f913f074fcb7 Mon Sep 17 00:00:00 2001 From: dfireBird Date: Mon, 8 Jun 2026 18:05:13 +0530 Subject: [PATCH 031/116] fix: use package id as argument to `--package` if package is not unique --- .../rust-analyzer/crates/rust-analyzer/src/target_spec.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs index 81d9786809b72..8e57d2df5296a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs @@ -319,7 +319,11 @@ impl CargoTargetSpec { pub(crate) fn push_to(self, buf: &mut Vec, kind: &RunnableKind) { buf.push("--package".to_owned()); - buf.push(self.package); + if self.package.contains(":") { + buf.push(self.package_id.to_string()); + } else { + buf.push(self.package); + } // Can't mix --doc with other target flags if let RunnableKind::DocTest { .. } = kind { From 40dc6719e051b1bedf2d80b8d96ba6e4ccb5def9 Mon Sep 17 00:00:00 2001 From: Lynn Gabbay Date: Fri, 12 Jun 2026 21:36:31 +0700 Subject: [PATCH 032/116] Don't count C-variadic `...` as a parameter for fn pointers When lowering a C-variadic function-pointer type such as `unsafe extern "C" fn(u8, ...) -> i32`, the `...` slot was being included in the lowered parameter list as a real input. The arity check then required the variadic slot to be supplied, producing a spurious E0107 ("wrong number of arguments") at the call site even though rustc accepts the code. The function-declaration lowering path already filters the variadic param out; this applies the same filtering to the fn-pointer path. Fixes rust-lang/rust-analyzer#22573 --- .../crates/hir-def/src/expr_store/lower.rs | 1 + .../src/handlers/mismatched_arg_count.rs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 3094e08a53c3c..bbc3f5333a14f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -671,6 +671,7 @@ impl<'db> ExprCollector<'db> { } pl.params() + .filter(|it| it.dotdotdot_token().is_none()) .map(|it| { let type_ref = self.lower_type_ref_opt(it.ty(), impl_trait_lower_fn); let name = match it.pat() { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index f6293e35d0c37..d1c3d1c5df096 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -354,6 +354,30 @@ fn f() { ) } + #[test] + fn varargs_fn_pointer() { + check_diagnostics( + r#" +struct Funcs { + f: unsafe extern "C" fn(u8, u8, ...) -> i32, + g: unsafe extern "C" fn(...) -> i32, +} + +fn f(funcs: Funcs) { + unsafe { + (funcs.f)(0, 1); + (funcs.f)(0, 1, 2); + (funcs.f)(0); + //^ error: expected 2 arguments, found 1 + (funcs.g)(); + (funcs.g)(0); + (funcs.g)(0, 1); + } +} + "#, + ) + } + #[test] fn arg_count_lambda() { check_diagnostics( From a52265f79332b2c31259cef5a90655a7b256904a Mon Sep 17 00:00:00 2001 From: Till Adam Date: Sat, 13 Jun 2026 09:53:36 +0200 Subject: [PATCH 033/116] perf: defer initial workspace flycheck until cache priming completes On startup the initial `cargo check` flycheck was launched in the same `became_quiescent` block as cache priming, so the two ran concurrently and fought for CPU. Neither is single-threaded: cache priming fans crate work across worker threads and `cargo check` spawns up to one rustc job per core, so running them together oversubscribes the cores. The effect is felt particularly on macOS, where rust-analyzer's priming threads run at `QOS_CLASS_UTILITY` (`ThreadIntent::Worker`) while the `cargo check` subprocess runs at the default, higher QoS -- so the scheduler starves priming (the work that makes the editor usable) in favour of the check. Move the initial workspace flycheck out of `became_quiescent` into the `PrimeCachesProgress::End` handler via a `pending_initial_flycheck` flag, so the check only starts once priming has finished; fall back to firing it immediately when cache priming is disabled. The flycheck still runs (cargo check begins right after indexing); diagnostics are deferred a beat, not lost. The impact depends on how much the startup `cargo check` has to compile: - Warm check (steady-state reopen): contention is negligible, so this is effectively neutral -- and harmless, deferring a fast check costs nothing. - Cold check (first open after clone / `git pull` / branch switch / toolchain change, where startup already hurts): large. Time-to-ready (cache priming complete) measured on macOS with a cold check, build scripts and proc-macros disabled to isolate the priming/check contention: rust-analyzer 74.8s -> 7.9s (~9.5x) slint 103.1s -> 26.6s (~3.9x) Flycheck slow-tests pass. Disclosure: prototyped with assistance from Claude (Anthropic); changes reviewed and owned by the committer. --- .../crates/rust-analyzer/src/main_loop.rs | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index edf3da5e6c07a..628e708c6a83d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -387,6 +387,16 @@ impl GlobalState { if cancelled { self.prime_caches_queue .request_op("restart after cancellation".to_owned(), ()); + } else if self.config.check_on_save(None) + && self.config.flycheck_workspace(None) + && !self.fetch_build_data_queue.op_requested() + { + // Priming finished; now run the deferred initial workspace flycheck + // (kept off the critical path so `cargo check` doesn't contend with + // cache priming for CPU). + self.flycheck + .iter() + .for_each(|flycheck| flycheck.restart_workspace(None)); } if let Some((message, fraction, title)) = last_report.take() { self.report_progress( @@ -482,13 +492,6 @@ impl GlobalState { if self.is_quiescent() { let became_quiescent = !was_quiescent; if became_quiescent { - if self.config.check_on_save(None) - && self.config.flycheck_workspace(None) - && !self.fetch_build_data_queue.op_requested() - { - // Project has loaded properly, kick off initial flycheck - self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None)); - } // delay initial cache priming until proc macros are loaded, or we will load up a bunch of garbage into salsa let proc_macros_loaded = self.config.prefill_caches() && (!self.config.expand_proc_macros() @@ -496,6 +499,19 @@ impl GlobalState { if proc_macros_loaded { self.prime_caches_queue.request_op("became quiescent".to_owned(), ()); } + if self.config.check_on_save(None) + && self.config.flycheck_workspace(None) + && !self.fetch_build_data_queue.op_requested() + { + if !self.config.prefill_caches() { + self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None)); + } else if proc_macros_loaded + && !self.prime_caches_queue.op_in_progress() + && !self.prime_caches_queue.op_requested() + { + self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None)); + } + } } let client_refresh = became_quiescent || state_changed; From cfdecac6a17e6d6f32a3bb3d1a860b4b1539848b Mon Sep 17 00:00:00 2001 From: eihqnh Date: Sun, 14 Jun 2026 00:59:37 +0800 Subject: [PATCH 034/116] fix: offer inline macro in macro call and proc macro --- .../ide-assists/src/handlers/inline_macro.rs | 67 ++++++++++++++++--- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs index 002791b88df64..f4ac75d2290dd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs @@ -1,8 +1,11 @@ use hir::db::ExpandDatabase; use ide_db::syntax_helpers::prettify_macro_expansion; -use syntax::ast::{self, AstNode, edit::AstNodeEdit}; +use syntax::ast::{self, AstNode, edit::IndentLevel}; -use crate::{AssistContext, AssistId, Assists}; +use crate::{ + AssistContext, AssistId, Assists, + utils::{cover_edit_range, original_range_in}, +}; // Assist: inline_macro // @@ -36,24 +39,40 @@ use crate::{AssistContext, AssistId, Assists}; // } // ``` pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> { - let unexpanded = ctx.find_node_at_offset::()?; - let macro_call = ctx.sema.to_def(&unexpanded)?; + let source = ctx.source_file().syntax(); + let sel = ctx.selection_trimmed(); + let (macro_call, text_range) = ctx + .sema + .find_nodes_at_offset_with_descend::(source, ctx.offset()) + .find_map(|macro_call_node| { + let macro_call = ctx.sema.to_def(¯o_call_node)?; + let original_range = + original_range_in(ctx.file_id(), &ctx.sema, macro_call_node.syntax())?; + original_range.contains_range(sel).then_some((macro_call, original_range)) + })?; let target_crate_id = ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate(ctx.db()).into(); - let text_range = unexpanded.syntax().text_range(); acc.add( AssistId::refactor_inline("inline_macro"), "Inline macro".to_owned(), text_range, |builder| { - let editor = builder.make_editor(unexpanded.syntax()); let expanded = ctx.sema.parse_or_expand(macro_call.into()); let span_map = ctx.sema.db.expansion_span_map(macro_call); // Don't call `prettify_macro_expansion()` outside the actual assist action; it does some heavy rowan tree manipulation, // which can be very costly for big macros when it is done *even without the assist being invoked*. let expanded = prettify_macro_expansion(ctx.db(), expanded, span_map, target_crate_id); - let expanded = ast::edit::indent(&expanded, unexpanded.indent_level()); - editor.replace(unexpanded.syntax(), expanded); + + // macro_call is from an expansion, use source position for indent + let indent = source + .token_at_offset(text_range.start()) + .right_biased() + .map_or_else(IndentLevel::zero, |t| IndentLevel::from_token(&t)); + let expanded = ast::edit::indent(&expanded, indent); + + let editor = builder.make_editor(source); + let place = cover_edit_range(source, text_range); + editor.replace_all(place, vec![expanded.into()]); builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) @@ -103,6 +122,7 @@ macro_rules! num { "# }; } + #[test] fn inline_macro_target() { check_assist_target( @@ -376,6 +396,37 @@ fn bar() { fn bar() { a::Foo; } +"#, + ); + } + + #[test] + fn inline_macro_in_macro() { + check_assist( + inline_macro, + r#" +macro_rules! foo { () => { 2 }; } +macro_rules! m { ($($tt:tt)*) => { $($tt)* }; } +fn f() { m! { $0foo!(); } } +"#, + r#" +macro_rules! foo { () => { 2 }; } +macro_rules! m { ($($tt:tt)*) => { $($tt)* }; } +fn f() { m! { 2; } } +"#, + ); + check_assist( + inline_macro, + r#" +//- proc_macros: identity +macro_rules! foo { () => { 2 }; } +#[proc_macros::identity] +fn f() { $0foo!(); } +"#, + r#" +macro_rules! foo { () => { 2 }; } +#[proc_macros::identity] +fn f() { 2; } "#, ); } From 95894614e7f7846b13935f990b1556af4bf2cf67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=BA=E4=B8=8D=E5=8F=AB=E5=8C=96=E5=92=95=E9=BE=99?= <1801943622@qq.com> Date: Sun, 14 Jun 2026 11:23:56 +0800 Subject: [PATCH 035/116] Use ASCII lowercase for file extensions --- .../crates/project-model/src/build_dependencies.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index e44af96f36435..352f41a82636a 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -560,7 +560,7 @@ impl WorkspaceBuildScripts { // FIXME: Find a better way to know if it is a dylib. fn is_dylib(path: &Utf8Path) -> bool { - match path.extension().map(|e| e.to_owned().to_lowercase()) { + match path.extension().map(|e| e.to_ascii_lowercase()) { None => false, Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"), } From d5755ebf8359ded61e26107c5c8112583174b095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 14 Jun 2026 15:14:53 +0200 Subject: [PATCH 036/116] Add funding links --- src/tools/rust-analyzer/.github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/tools/rust-analyzer/.github/FUNDING.yml diff --git a/src/tools/rust-analyzer/.github/FUNDING.yml b/src/tools/rust-analyzer/.github/FUNDING.yml new file mode 100644 index 0000000000000..1d270e78949f8 --- /dev/null +++ b/src/tools/rust-analyzer/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: rustfoundation +custom: ["rust-lang.org/funding"] From dc39c189e68eec68a76a504fd102ac7d52209881 Mon Sep 17 00:00:00 2001 From: dfireBird Date: Sat, 13 Jun 2026 02:52:47 +0530 Subject: [PATCH 037/116] fix: prefer bench command when target is bench to avoid cargo run --- .../rust-analyzer/crates/rust-analyzer/src/target_spec.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs index 81d9786809b72..31f798d0c9548 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs @@ -153,6 +153,9 @@ impl CargoTargetSpec { Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => { config.test_command } + Some(CargoTargetSpec { target_kind: TargetKind::Bench, .. }) => { + config.bench_command + } _ => "run".to_owned(), }; cargo_args.push(subcommand); @@ -225,6 +228,9 @@ impl CargoTargetSpec { Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => { (config.test_override_command, None) } + Some(CargoTargetSpec { target_kind: TargetKind::Bench, .. }) => { + (config.bench_override_command, None) + } _ => (None, None), }, }; From 5ffbf047faed9e481593c898108f6b4efa1e717d Mon Sep 17 00:00:00 2001 From: cyrgani Date: Sat, 30 May 2026 11:46:32 +0000 Subject: [PATCH 038/116] remove some redundant closures --- library/proc_macro/src/bridge/client.rs | 2 +- library/proc_macro/src/lib.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index a5966f767596e..48e6245ecf98b 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -282,7 +282,7 @@ impl Client { pub const fn expand1(f: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy) -> Self { Client { run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |input| f(input)) + run_client(bridge, f) }), } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index e335fe1c70264..317b4de4e338e 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -295,7 +295,7 @@ impl TokenStream { /// Checks if this `TokenStream` is empty. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn is_empty(&self) -> bool { - self.0.as_ref().map(|h| BridgeMethods::ts_is_empty(h)).unwrap_or(true) + self.0.as_ref().map(BridgeMethods::ts_is_empty).unwrap_or(true) } /// Parses this `TokenStream` as an expression and attempts to expand any @@ -574,9 +574,7 @@ pub mod token_stream { type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { - IntoIter( - self.0.map(|v| BridgeMethods::ts_into_trees(v)).unwrap_or_default().into_iter(), - ) + IntoIter(self.0.map(BridgeMethods::ts_into_trees).unwrap_or_default().into_iter()) } } } From acac5b30365c341df137c2df40acd218305b4f3c Mon Sep 17 00:00:00 2001 From: cyrgani Date: Sat, 30 May 2026 21:38:30 +0000 Subject: [PATCH 039/116] simplify `Buffer` --- library/proc_macro/src/bridge/buffer.rs | 32 ++----------------------- library/proc_macro/src/bridge/rpc.rs | 3 +-- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index 3760749d83a54..3176b9ea35c8c 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -1,8 +1,7 @@ //! Buffer management for same-process client<->server communication. -use std::io::{self, Write}; use std::mem::{self, ManuallyDrop}; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::slice; #[repr(C)] @@ -32,13 +31,6 @@ impl Deref for Buffer { } } -impl DerefMut for Buffer { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.data, self.len) } - } -} - impl Buffer { #[inline] pub(super) fn new() -> Self { @@ -99,25 +91,6 @@ impl Buffer { } } -impl Write for Buffer { - #[inline] - fn write(&mut self, xs: &[u8]) -> io::Result { - self.extend_from_slice(xs); - Ok(xs.len()) - } - - #[inline] - fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { - self.extend_from_slice(xs); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - impl Drop for Buffer { #[inline] fn drop(&mut self) { @@ -128,8 +101,7 @@ impl Drop for Buffer { impl From> for Buffer { fn from(v: Vec) -> Self { - let mut v = ManuallyDrop::new(v); - let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); + let (data, len, capacity) = v.into_raw_parts(); // This utility function is nested in here because it can *only* // be safely called on `Buffer`s created by *this* `proc_macro`. diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 3459426b5cd3f..2c72497ad2723 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -1,6 +1,5 @@ //! Serialization for client-server communication. -use std::io::Write; use std::num::NonZero; use super::buffer::Buffer; @@ -209,7 +208,7 @@ impl Encode for &str { fn encode(self, w: &mut Buffer, s: &mut S) { let bytes = self.as_bytes(); bytes.len().encode(w, s); - w.write_all(bytes).unwrap(); + w.extend_from_slice(bytes); } } From d727a0e22414efd3f7f925424216daec4a505cab Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 1 Jun 2026 11:51:57 +0000 Subject: [PATCH 040/116] set `issue = none` for `proc_macro_internals` --- library/proc_macro/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 317b4de4e338e..4ead52e533e5d 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -37,7 +37,7 @@ #![warn(unreachable_pub)] #![deny(unsafe_op_in_unsafe_fn)] -#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[unstable(feature = "proc_macro_internals", issue = "none")] #[doc(hidden)] pub mod bridge; @@ -592,7 +592,7 @@ pub macro quote($($t:tt)*) { /* compiler built-in */ } -#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[unstable(feature = "proc_macro_internals", issue = "none")] #[doc(hidden)] mod quote; @@ -752,14 +752,14 @@ impl Span { // Used by the implementation of `Span::quote` #[doc(hidden)] - #[unstable(feature = "proc_macro_internals", issue = "27812")] + #[unstable(feature = "proc_macro_internals", issue = "none")] pub fn save_span(&self) -> usize { BridgeMethods::span_save_span(self.0) } // Used by the implementation of `Span::quote` #[doc(hidden)] - #[unstable(feature = "proc_macro_internals", issue = "27812")] + #[unstable(feature = "proc_macro_internals", issue = "none")] pub fn recover_proc_macro_span(id: usize) -> Span { Span(BridgeMethods::span_recover_proc_macro_span(id)) } From b292ff80a2a64ed136a7075c5fbb0d4e6661c06b Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 8 Jun 2026 09:11:17 +0000 Subject: [PATCH 041/116] fix "rountrips" typo --- library/proc_macro/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 4ead52e533e5d..54ade77f86780 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1293,7 +1293,7 @@ macro_rules! unsuffixed_int_literals { /// specified on this token, meaning that invocations like /// `Literal::i8_unsuffixed(1)` are equivalent to /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers might not survive rountrips through + /// Literals created from negative numbers might not survive roundtrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// Literals created through this method have the `Span::call_site()` @@ -1413,7 +1413,7 @@ impl Literal { /// This constructor is similar to those like `Literal::i8_unsuffixed` where /// the float's value is emitted directly into the token but no suffix is /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through + /// Literals created from negative numbers might not survive roundtrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics @@ -1438,7 +1438,7 @@ impl Literal { /// specified is the preceding part of the token and `f32` is the suffix of /// the token. This token will always be inferred to be an `f32` in the /// compiler. - /// Literals created from negative numbers might not survive rountrips through + /// Literals created from negative numbers might not survive roundtrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics @@ -1458,7 +1458,7 @@ impl Literal { /// This constructor is similar to those like `Literal::i8_unsuffixed` where /// the float's value is emitted directly into the token but no suffix is /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through + /// Literals created from negative numbers might not survive roundtrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics @@ -1483,7 +1483,7 @@ impl Literal { /// specified is the preceding part of the token and `f64` is the suffix of /// the token. This token will always be inferred to be an `f64` in the /// compiler. - /// Literals created from negative numbers might not survive rountrips through + /// Literals created from negative numbers might not survive roundtrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics From 30004a85b3c636d395180850cafdab91d3cb6367 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 8 Jun 2026 09:11:29 +0000 Subject: [PATCH 042/116] improve `nonfatal-parsing` test --- .../auxiliary/nonfatal-parsing-body.rs | 33 +++++-- tests/ui/proc-macro/nonfatal-parsing.stderr | 26 +++++- tests/ui/proc-macro/nonfatal-parsing.stdout | 92 ++++++++++--------- 3 files changed, 102 insertions(+), 49 deletions(-) diff --git a/tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs b/tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs index f58aa1b228e31..258f77067ce9c 100644 --- a/tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs +++ b/tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs @@ -15,26 +15,38 @@ enum Mode { OtherWithPanic, } +fn print_unspanned(s: &str) -> Result +where + T: FromStr + Debug, +{ + let t = T::from_str(s); + let mut s = format!("{t:?}"); + while let Some((l, r)) = s.split_once("span: #") { + let (_, r) = r.split_once(")").unwrap(); + s = format!("{l}span: Span{r}"); + } + println!("{s}"); + t +} + fn parse(s: &str, mode: Mode) where T: FromStr + Debug, { match mode { NormalOk => { - let t = T::from_str(s); - println!("{:?}", t); + let t = print_unspanned::(s); assert!(t.is_ok()); } NormalErr => { - let t = T::from_str(s); - println!("{:?}", t); + let t = print_unspanned::(s); assert!(t.is_err()); } OtherError => { - println!("{:?}", T::from_str(s)); + print_unspanned::(s); } OtherWithPanic => { - if catch_unwind(|| println!("{:?}", T::from_str(s))).is_ok() { + if catch_unwind(|| print_unspanned::(s)).is_ok() { eprintln!("{s} did not panic"); } } @@ -64,7 +76,10 @@ fn lit(s: &str, mode: Mode) { } pub fn run() { + assert_eq!("\'", "'"); // returns Ok(valid instance) + lit("r\"g\"", NormalOk); + lit("r#\"g\"#", NormalOk); lit("123", NormalOk); lit("\"ab\"", NormalOk); lit("\'b\'", NormalOk); @@ -72,6 +87,7 @@ pub fn run() { lit("b\"b\"", NormalOk); lit("c\"b\"", NormalOk); lit("cr\"b\"", NormalOk); + lit("'\\''", NormalOk); lit("b'b'", NormalOk); lit("256u8", NormalOk); lit("-256u8", NormalOk); @@ -99,10 +115,13 @@ pub fn run() { NormalOk, ); stream("/*a*/ //", NormalOk); + lit("\"\"", NormalOk); + stream("", NormalOk); println!("### ERRORS"); // returns Err(LexError) + lit("", NormalErr); lit("\'c\'/**/", NormalErr); lit(" 0", NormalErr); lit("0 ", NormalErr); @@ -119,10 +138,12 @@ pub fn run() { // emits diagnostics and returns LexError lit("r'r'", OtherError); lit("c'r'", OtherError); + lit("\u{2000}", OtherError); // emits diagnostic and returns a seemingly valid tokenstream stream("r'r'", OtherError); stream("c'r'", OtherError); + stream("\u{2000}", OtherError); for parse in [stream as fn(&str, Mode), lit] { // emits diagnostic(s), then panics diff --git a/tests/ui/proc-macro/nonfatal-parsing.stderr b/tests/ui/proc-macro/nonfatal-parsing.stderr index 874a7a2f410d9..cb6e243eebc9b 100644 --- a/tests/ui/proc-macro/nonfatal-parsing.stderr +++ b/tests/ui/proc-macro/nonfatal-parsing.stderr @@ -22,6 +22,17 @@ help: consider inserting whitespace here LL | c 'r' | + +error: unknown start of token: \u{2000} + --> :1:1 + | +LL |   + | ^ + | +help: Unicode character ' ' (En Quad) looks like ' ' (Space), but it is not + | +LL | + | + error: prefix `r` is unknown --> $DIR/nonfatal-parsing.rs:15:5 | @@ -40,6 +51,19 @@ LL | nonfatal_parsing::run!(); = note: prefixed identifiers and literals are reserved since Rust 2021 = note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info) +error: unknown start of token: \u{2000} + --> $DIR/nonfatal-parsing.rs:15:5 + | +LL | nonfatal_parsing::run!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info) +help: Unicode character ' ' (En Quad) looks like ' ' (Space), but it is not + --> :1:1 + | +LL | + | + error: found invalid character; only `#` is allowed in raw string delimitation: \u{0} --> $DIR/nonfatal-parsing.rs:15:5 | @@ -175,6 +199,6 @@ error: invalid digit for a base 2 literal LL | /*a*/ 0b2 // | ^ -error: aborting due to 20 previous errors +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0768`. diff --git a/tests/ui/proc-macro/nonfatal-parsing.stdout b/tests/ui/proc-macro/nonfatal-parsing.stdout index 2b92474fb8b4c..a46ef66f0f9d0 100644 --- a/tests/ui/proc-macro/nonfatal-parsing.stdout +++ b/tests/ui/proc-macro/nonfatal-parsing.stdout @@ -1,34 +1,40 @@ -Ok(Literal { kind: Integer, symbol: "123", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Str, symbol: "ab", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: ByteStr, symbol: "b", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: CStr, symbol: "b", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: CStrRaw(0), symbol: "b", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Byte, symbol: "b", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #44 bytes(361..385) }) -Ok(Literal { kind: Integer, symbol: "-256", suffix: Some("u8"), span: #44 bytes(361..385) }) -Ok(TokenStream [Punct { ch: '-', spacing: Alone, span: #44 bytes(361..385) }, Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #44 bytes(361..385) }]) -Ok(Literal { kind: Integer, symbol: "0b11111000000001111", suffix: Some("i16"), span: #44 bytes(361..385) }) -Ok(Literal { kind: Integer, symbol: "0xf32", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Integer, symbol: "0b0", suffix: Some("f32"), span: #44 bytes(361..385) }) -Ok(Literal { kind: Float, symbol: "2E4", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Float, symbol: "2.2E-4", suffix: Some("f64"), span: #44 bytes(361..385) }) -Ok(Literal { kind: Integer, symbol: "18", suffix: Some("u8E"), span: #44 bytes(361..385) }) -Ok(Literal { kind: Float, symbol: "18.0", suffix: Some("u8E"), span: #44 bytes(361..385) }) -Ok(Literal { kind: CStrRaw(1), symbol: "// /* // \n */", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: StrRaw(255), symbol: "a", suffix: None, span: #44 bytes(361..385) }) -Ok(TokenStream [Ident { ident: "fn", span: #44 bytes(361..385) }, Ident { ident: "main", span: #44 bytes(361..385) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #44 bytes(361..385) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "println", span: #44 bytes(361..385) }, Punct { ch: '!', spacing: Alone, span: #44 bytes(361..385) }, Group { delimiter: Parenthesis, stream: TokenStream [Literal { kind: Str, symbol: "Hello, world!", suffix: None, span: #44 bytes(361..385) }], span: #44 bytes(361..385) }], span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #44 bytes(361..385) }, Punct { ch: '.', spacing: Alone, span: #44 bytes(361..385) }, Ident { ident: "u8E", span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f32"), span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f34"), span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #44 bytes(361..385) }, Punct { ch: '.', spacing: Alone, span: #44 bytes(361..385) }, Ident { ident: "bu8", span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: Integer, symbol: "3", suffix: None, span: #44 bytes(361..385) }, Literal { kind: Integer, symbol: "4", suffix: None, span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: Char, symbol: "c", suffix: None, span: #44 bytes(361..385) }]) +Ok(Literal { kind: StrRaw(0), symbol: "g", suffix: None, span: Span }) +Ok(Literal { kind: StrRaw(1), symbol: "g", suffix: None, span: Span }) +Ok(Literal { kind: Integer, symbol: "123", suffix: None, span: Span }) +Ok(Literal { kind: Str, symbol: "ab", suffix: None, span: Span }) +Ok(Literal { kind: Char, symbol: "b", suffix: None, span: Span }) +Ok(Literal { kind: Char, symbol: "b", suffix: None, span: Span }) +Ok(Literal { kind: ByteStr, symbol: "b", suffix: None, span: Span }) +Ok(Literal { kind: CStr, symbol: "b", suffix: None, span: Span }) +Ok(Literal { kind: CStrRaw(0), symbol: "b", suffix: None, span: Span }) +Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: Span }) +Ok(Literal { kind: Byte, symbol: "b", suffix: None, span: Span }) +Ok(Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: Span }) +Ok(Literal { kind: Integer, symbol: "-256", suffix: Some("u8"), span: Span }) +Ok(TokenStream [Punct { ch: '-', spacing: Alone, span: Span }, Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: Span }]) +Ok(Literal { kind: Integer, symbol: "0b11111000000001111", suffix: Some("i16"), span: Span }) +Ok(Literal { kind: Integer, symbol: "0xf32", suffix: None, span: Span }) +Ok(Literal { kind: Integer, symbol: "0b0", suffix: Some("f32"), span: Span }) +Ok(Literal { kind: Float, symbol: "2E4", suffix: None, span: Span }) +Ok(Literal { kind: Float, symbol: "2.2E-4", suffix: Some("f64"), span: Span }) +Ok(Literal { kind: Integer, symbol: "18", suffix: Some("u8E"), span: Span }) +Ok(Literal { kind: Float, symbol: "18.0", suffix: Some("u8E"), span: Span }) +Ok(Literal { kind: CStrRaw(1), symbol: "// /* // \n */", suffix: None, span: Span }) +Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: Span }) +Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: Span }) +Ok(Literal { kind: StrRaw(255), symbol: "a", suffix: None, span: Span }) +Ok(TokenStream [Ident { ident: "fn", span: Span }, Ident { ident: "main", span: Span }, Group { delimiter: Parenthesis, stream: TokenStream [], span: Span }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "println", span: Span }, Punct { ch: '!', spacing: Alone, span: Span }, Group { delimiter: Parenthesis, stream: TokenStream [Literal { kind: Str, symbol: "Hello, world!", suffix: None, span: Span }], span: Span }], span: Span }]) +Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: Span }, Punct { ch: '.', spacing: Alone, span: Span }, Ident { ident: "u8E", span: Span }]) +Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f32"), span: Span }]) +Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f34"), span: Span }]) +Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: Span }, Punct { ch: '.', spacing: Alone, span: Span }, Ident { ident: "bu8", span: Span }]) +Ok(TokenStream [Literal { kind: Integer, symbol: "3", suffix: None, span: Span }, Literal { kind: Integer, symbol: "4", suffix: None, span: Span }]) +Ok(TokenStream [Literal { kind: Char, symbol: "c", suffix: None, span: Span }]) +Ok(TokenStream []) +Ok(Literal { kind: Str, symbol: "", suffix: None, span: Span }) Ok(TokenStream []) ### ERRORS +Err(LexError("not a literal")) Err(LexError("comment or whitespace around literal")) Err(LexError("comment or whitespace around literal")) Err(LexError("comment or whitespace around literal")) @@ -42,17 +48,19 @@ Err(LexError("unexpected closing delimiter: `)`")) Err(LexError("unexpected closing delimiter: `]`")) Err(LexError("not a literal")) Err(LexError("not a literal")) -Ok(TokenStream [Ident { ident: "r", span: #44 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #44 bytes(361..385) }]) -Ok(TokenStream [Ident { ident: "c", span: #44 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #44 bytes(361..385) }]) -Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) }]) -Ok(Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #44 bytes(361..385) }) -Ok(Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #44 bytes(361..385) }) -Ok(Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #44 bytes(361..385) }) -Ok(Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #44 bytes(361..385) }) +Err(LexError("not a literal")) +Ok(TokenStream [Ident { ident: "r", span: Span }, Literal { kind: Char, symbol: "r", suffix: None, span: Span }]) +Ok(TokenStream [Ident { ident: "c", span: Span }, Literal { kind: Char, symbol: "r", suffix: None, span: Span }]) +Ok(TokenStream []) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: Span }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: Span }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: Span }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: Span }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: Span }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: Span }]) +Ok(Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: Span }) +Ok(Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: Span }) +Ok(Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: Span }) +Ok(Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: Span }) +Ok(Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: Span }) Err(LexError("comment or whitespace around literal")) From a39003660da2f444a518b8593d2aba66705bc9da Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Mon, 15 Jun 2026 11:59:10 -0300 Subject: [PATCH 043/116] resolve region inference vars when computing their max universe The `MaxUniverse` region visitor matched on `ReVar` terms and unwrapped `universe_of_lt`, which returns `None` for a variable that has already been unified with another region. Such resolved variables can reach the visitor while computing region assumptions under `-Zassumptions-on-binders`, causing an ICE. Resolve the variable first and inspect whatever it points at instead of assuming it is still an unresolved inference variable. --- .../rustc_type_ir/src/region_constraint.rs | 23 +++++++++++++--- .../resolved-region-var-max-universe.rs | 26 +++++++++++++++++++ .../resolved-region-var-max-universe.stderr | 14 ++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs create mode 100644 tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 4b23bfd0f7765..6f13eedda4983 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -1013,6 +1013,10 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match t.kind() { TyKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), TyKind::Infer(InferTy::TyVar(inf)) => { + // Unlike `visit_region`, we don't resolve the variable first: callers + // computing assumptions bail on any non-region inference variable + // before reaching here, so a type infer var is always unresolved and + // has a universe. let u = self.infcx.universe_of_ty(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1025,6 +1029,8 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match c.kind() { ConstKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), ConstKind::Infer(rustc_type_ir::InferConst::Var(inf)) => { + // See the comment in `visit_ty`: a const infer var is always + // unresolved here, so unlike a region it needs no resolving first. let u = self.infcx.universe_of_ct(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1037,9 +1043,20 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match r.kind() { RegionKind::RePlaceholder(p) => self.max_universe = self.max_universe.max(p.universe), RegionKind::ReVar(var) => { - let u = self.infcx.universe_of_lt(var).unwrap(); - debug!("var {var:?} in universe {u:?}"); - self.max_universe = self.max_universe.max(u); + // The variable may already have been unified with another region. + // `universe_of_lt` returns `None` for a resolved variable, so resolve + // it first and inspect whatever it points at. + match self.infcx.opportunistic_resolve_lt_var(var).kind() { + RegionKind::RePlaceholder(p) => { + self.max_universe = self.max_universe.max(p.universe) + } + RegionKind::ReVar(var) => { + let u = self.infcx.universe_of_lt(var).unwrap(); + debug!("var {var:?} in universe {u:?}"); + self.max_universe = self.max_universe.max(u); + } + _ => (), + } } _ => (), } diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs new file mode 100644 index 0000000000000..f0286fb92453a --- /dev/null +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +// Regression test for an ICE in the `MaxUniverse` region visitor. When computing +// the max universe of a region constraint, a `ReVar` term could already have been +// unified with another region. `universe_of_lt` returns `None` for such a resolved +// variable, so the visitor used to `unwrap()` `None` and panic. It now resolves the +// variable before inspecting its universe. + +#![feature(min_generic_const_args, inherent_associated_types, generic_const_items)] + +struct Parent<'a> { + a: &'a str, +} + +impl<'a> Parent<'a> { + type const CT: usize = 0; +} + +fn check/**/() +where + [(); Parent::CT::]:, + //~^ ERROR cannot find type `T` in this scope +{ +} + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr new file mode 100644 index 0000000000000..6fa91876dd47b --- /dev/null +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find type `T` in this scope + --> $DIR/resolved-region-var-max-universe.rs:21:23 + | +LL | [(); Parent::CT::]:, + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn check/**/() + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. From 6f2ad7dcc51e60c5d6f0ea1638dbda709d9c8492 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 15 Jun 2026 19:49:58 -0400 Subject: [PATCH 044/116] Make `char::is_private_use` unstably public --- library/core/src/char/methods.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 8c5f9d472bfa8..4edcd3633a91b 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1139,8 +1139,9 @@ impl char { /// [`UnicodeData.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt /// #[must_use] + #[unstable(feature = "char_unassigned_private_use", issue = "none")] #[inline] - const fn is_private_use(self) -> bool { + pub const fn is_private_use(self) -> bool { // According to // https://www.unicode.org/policies/stability_policy.html#Property_Value, // the set of codepoints in `Co` will never change. From 3bea8e32aeb195ae07b53d1beefd3ca378b5b22e Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 15 Jun 2026 19:51:34 -0400 Subject: [PATCH 045/116] Change `char::is_unassigned` to `is_assigned`, & make it unstably public --- library/core/src/char/methods.rs | 48 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 4edcd3633a91b..8e25320b6b268 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -495,7 +495,7 @@ impl char { || args.escape_grapheme_extender && self.is_grapheme_extender() || self.is_default_ignorable() || self.is_format_control() - || self.is_unassigned() => + || !self.is_assigned() => { EscapeDebug::unicode(self) } @@ -1177,54 +1177,56 @@ impl char { self > '\u{AC}' && unicode::Cf(self) } - /// Returns `true` if this `char` has not yet been assigned a meaning by Unicode, as of + /// Returns `true` if this `char` has been assigned a meaning by Unicode, as of /// [`UNICODE_VERSION`]. /// /// [`UNICODE_VERSION`]: Self::UNICODE_VERSION /// - /// These characters may have a meaning assigned in the future, - /// except for the 66 [noncharacters] which will never be assigned a meaning. - /// - /// [noncharacters]: https://www.unicode.org/faq/private_use#noncharacters - /// /// Many of Unicode's [stability policies] apply only to assigned characters. /// /// [stability policies]: https://www.unicode.org/policies/stability_policy.html /// - /// Unassigned characters (code points with the general category of `Cn`) are [described] in Chapter 4 - /// (Character Properties) of the Unicode Standard, and [specified] in the Unicode Character Database - /// by their exclusion from [`UnicodeData.txt`]. + /// Currently unassigned characters (characters for which this method returns `false`) + /// may have a meaning assigned in a future version of Unicode, + /// except for the 66 [noncharacters] which will never be assigned a meaning. + /// + /// [noncharacters]: https://www.unicode.org/faq/private_use.html#noncharacters + /// + /// A character is considered assigned if it is present in [`UnicodeData.txt`]. + /// Unassigned characters have general category `Cn`, as [described] in Chapter 4 + /// (Character Properties) of the Unicode Standard. /// - /// [described]: https://www.unicode.org/versions/latest/core-spec/chapter-4/#G134153 - /// [specified]: https://www.unicode.org/reports/tr44/#GC_Values_Table /// [`UnicodeData.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt + /// [described]: https://www.unicode.org/versions/latest/core-spec/chapter-4/#G134153 /// /// # Examples /// /// Basic usage: /// - /// ```ignore(private) - /// assert!('\u{FFFE}'.is_unassigned()); // noncharacter, will never be assigned - /// - /// //assert!('\u{7AAAA}'.is_unassigned()); // not currently assigned, but may be in the future, - /// // so we shouldn't rely on the current status + /// ``` + /// #![feature(char_unassigned_private_use)] + /// assert!('γ'.is_assigned()); // once a character is assigned, it stays assigned forever + /// assert!(!'\u{FFFE}'.is_assigned()); // noncharacter, will never be assigned /// - /// assert!(!'γ'.is_unassigned()); // once a character is assigned, it stays assigned forever + /// // Not currently assigned, but may be in the future, + /// // so we shouldn't rely on the current status + /// /* assert!(!'\u{7AAAA}'.is_assigned()); */ /// ``` #[must_use] + #[unstable(feature = "char_unassigned_private_use", issue = "none")] #[inline] - fn is_unassigned(self) -> bool { + pub fn is_assigned(self) -> bool { match self { - '\0'..='\u{377}' => false, - '\u{378}'..='\u{3FFFD}' => unicode::Cn_planes_0_3(self), + '\0'..='\u{377}' => true, + '\u{378}'..='\u{3FFFD}' => !unicode::Cn_planes_0_3(self), // Assigned character ranges in planes 4 and above. // `src/tools/unicode-table-generator/src/main.rs` asserts that this is correct '\u{E0001}' | '\u{E0020}'..='\u{E007F}' | '\u{E0100}'..='\u{E01EF}' | '\u{F0000}'..='\u{FFFFD}' - | '\u{100000}'..='\u{10FFFD}' => false, - _ => true, + | '\u{100000}'..='\u{10FFFD}' => true, + _ => false, } } From 527465693f233d4c72ca30d2a8835f9e9d9389c7 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Tue, 16 Jun 2026 15:41:47 +0100 Subject: [PATCH 046/116] fix: MIR eval mixed bit and byte sizes MIR eval was using .bit_width() and then Size::from_bytes(), leading to sizes that were out by a factor of 8. This led to crashes like "expected int of size 64, but got size 8" during const eval. I initially noticed this with u64 (a type of known size, so .bit_size() returned a non-None value) but I've fixed all the bit/byte mismatches in MIR evaluation. Also added a unit test with a minimal repro of the case I originally saw. Fixes rust-lang/rust-analyzer#22593 AI disclosure: Partially written with Codex and GPT 5.5. --- .../crates/hir-ty/src/consteval/tests.rs | 13 +++++ .../crates/hir-ty/src/mir/eval.rs | 52 +++++++++++-------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 5421b97db2386..0e51594a78d06 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -2633,6 +2633,19 @@ fn const_generic_subst_fn() { ); } +#[test] +fn const_generic_fixed_width() { + check_number( + r#" + const fn m() -> u64 { + N + } + const GOAL: u64 = m::<0>(); + "#, + 0, + ); +} + #[test] fn layout_of_type_with_associated_type_field_defined_inside_body() { check_number( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index eb0e4c60200f2..c69febd019672 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -1935,25 +1935,37 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { Ok(Interval::new(addr, 4)) } TyKind::Int(int_ty) => { - let size = int_ty.bit_width().unwrap_or(self.ptr_size() as u64); - let value = valtree.inner().to_leaf().to_int(Size::from_bytes(size)); - let addr = self.heap_allocate(size as usize, size as usize)?; - self.write_memory(addr, &value.to_le_bytes()[..size as usize])?; - Ok(Interval::new(addr, size as usize)) + let size = int_ty + .bit_width() + .map(Size::from_bits) + .unwrap_or_else(|| Size::from_bytes(self.ptr_size() as u64)); + let bytes = size.bytes_usize(); + + let value = valtree.inner().to_leaf().to_int(size); + let addr = self.heap_allocate(bytes, bytes)?; + self.write_memory(addr, &value.to_le_bytes()[..bytes])?; + Ok(Interval::new(addr, bytes)) } TyKind::Uint(uint_ty) => { - let size = uint_ty.bit_width().unwrap_or(self.ptr_size() as u64); - let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size)); - let addr = self.heap_allocate(size as usize, size as usize)?; - self.write_memory(addr, &value.to_le_bytes()[..size as usize])?; - Ok(Interval::new(addr, size as usize)) + let size = uint_ty + .bit_width() + .map(Size::from_bits) + .unwrap_or_else(|| Size::from_bytes(self.ptr_size() as u64)); + let bytes = size.bytes_usize(); + + let value = valtree.inner().to_leaf().to_uint(size); + let addr = self.heap_allocate(bytes, bytes)?; + self.write_memory(addr, &value.to_le_bytes()[..bytes])?; + Ok(Interval::new(addr, bytes)) } TyKind::Float(float_ty) => { - let size = float_ty.bit_width(); - let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size)); - let addr = self.heap_allocate(size as usize, size as usize)?; - self.write_memory(addr, &value.to_le_bytes()[..size as usize])?; - Ok(Interval::new(addr, size as usize)) + let size = Size::from_bits(float_ty.bit_width()); + let bytes = size.bytes_usize(); + + let value = valtree.inner().to_leaf().to_uint(size); + let addr = self.heap_allocate(bytes, bytes)?; + self.write_memory(addr, &value.to_le_bytes()[..bytes])?; + Ok(Interval::new(addr, bytes)) } TyKind::RawPtr(..) => { let size = self.ptr_size(); @@ -1995,15 +2007,13 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { _ => not_supported!("unsupported const"), }) .collect::>>()?; + let item_size = item_layout.size.bytes_usize(); let items_addr = self.heap_allocate( - items.len() * (item_layout.size.bits() as usize), - item_layout.align.bits_usize(), + items.len() * item_size, + item_layout.align.bytes() as usize, )?; for (i, item) in items.iter().enumerate() { - self.copy_from_interval( - items_addr.offset(i * (item_layout.size.bits() as usize)), - *item, - )?; + self.copy_from_interval(items_addr.offset(i * item_size), *item)?; } let ref_addr = self.heap_allocate(self.ptr_size() * 2, self.ptr_size())?; self.write_memory(ref_addr, &items_addr.to_bytes())?; From ae9501c925412fddacb396a5950324804b33b8df Mon Sep 17 00:00:00 2001 From: zedddie Date: Wed, 17 Jun 2026 05:39:16 +0200 Subject: [PATCH 047/116] move batch --- .../assoc-type-projection-in-default-method.rs} | 0 .../associated-type-projection-alias-in-field.rs} | 0 .../issue-22629.rs => associated-types/normalize-assoc-types.rs} | 0 .../issue-22258.rs => associated-types/ret-associated-type.rs} | 0 .../supertrait-bound-references-own-associated-type.rs} | 0 .../no-dropck-overflow-on-deep-nesting.rs} | 0 .../infinite-instantiation-via-nested-closures.rs} | 0 .../infinite-instantiation-via-nested-closures.stderr} | 0 .../where-clause-on-generic-type-alias.rs} | 0 .../fnonce-impl-on-unit-struct.rs} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-22036.rs => associated-types/assoc-type-projection-in-default-method.rs} (100%) rename tests/ui/{issues/issue-22356.rs => associated-types/associated-type-projection-alias-in-field.rs} (100%) rename tests/ui/{issues/issue-22629.rs => associated-types/normalize-assoc-types.rs} (100%) rename tests/ui/{issues/issue-22258.rs => associated-types/ret-associated-type.rs} (100%) rename tests/ui/{issues/issue-22673.rs => associated-types/supertrait-bound-references-own-associated-type.rs} (100%) rename tests/ui/{issues/issue-22777.rs => dropck/no-dropck-overflow-on-deep-nesting.rs} (100%) rename tests/ui/{issues/issue-22638.rs => recursion/infinite-instantiation-via-nested-closures.rs} (100%) rename tests/ui/{issues/issue-22638.stderr => recursion/infinite-instantiation-via-nested-closures.stderr} (100%) rename tests/ui/{issues/issue-22471.rs => type-alias/where-clause-on-generic-type-alias.rs} (100%) rename tests/ui/{issues/issue-22603.rs => unboxed-closures/fnonce-impl-on-unit-struct.rs} (100%) diff --git a/tests/ui/issues/issue-22036.rs b/tests/ui/associated-types/assoc-type-projection-in-default-method.rs similarity index 100% rename from tests/ui/issues/issue-22036.rs rename to tests/ui/associated-types/assoc-type-projection-in-default-method.rs diff --git a/tests/ui/issues/issue-22356.rs b/tests/ui/associated-types/associated-type-projection-alias-in-field.rs similarity index 100% rename from tests/ui/issues/issue-22356.rs rename to tests/ui/associated-types/associated-type-projection-alias-in-field.rs diff --git a/tests/ui/issues/issue-22629.rs b/tests/ui/associated-types/normalize-assoc-types.rs similarity index 100% rename from tests/ui/issues/issue-22629.rs rename to tests/ui/associated-types/normalize-assoc-types.rs diff --git a/tests/ui/issues/issue-22258.rs b/tests/ui/associated-types/ret-associated-type.rs similarity index 100% rename from tests/ui/issues/issue-22258.rs rename to tests/ui/associated-types/ret-associated-type.rs diff --git a/tests/ui/issues/issue-22673.rs b/tests/ui/associated-types/supertrait-bound-references-own-associated-type.rs similarity index 100% rename from tests/ui/issues/issue-22673.rs rename to tests/ui/associated-types/supertrait-bound-references-own-associated-type.rs diff --git a/tests/ui/issues/issue-22777.rs b/tests/ui/dropck/no-dropck-overflow-on-deep-nesting.rs similarity index 100% rename from tests/ui/issues/issue-22777.rs rename to tests/ui/dropck/no-dropck-overflow-on-deep-nesting.rs diff --git a/tests/ui/issues/issue-22638.rs b/tests/ui/recursion/infinite-instantiation-via-nested-closures.rs similarity index 100% rename from tests/ui/issues/issue-22638.rs rename to tests/ui/recursion/infinite-instantiation-via-nested-closures.rs diff --git a/tests/ui/issues/issue-22638.stderr b/tests/ui/recursion/infinite-instantiation-via-nested-closures.stderr similarity index 100% rename from tests/ui/issues/issue-22638.stderr rename to tests/ui/recursion/infinite-instantiation-via-nested-closures.stderr diff --git a/tests/ui/issues/issue-22471.rs b/tests/ui/type-alias/where-clause-on-generic-type-alias.rs similarity index 100% rename from tests/ui/issues/issue-22471.rs rename to tests/ui/type-alias/where-clause-on-generic-type-alias.rs diff --git a/tests/ui/issues/issue-22603.rs b/tests/ui/unboxed-closures/fnonce-impl-on-unit-struct.rs similarity index 100% rename from tests/ui/issues/issue-22603.rs rename to tests/ui/unboxed-closures/fnonce-impl-on-unit-struct.rs From 9e59547c16db00f1dcc076c8a83284cfec8cbf06 Mon Sep 17 00:00:00 2001 From: zedddie Date: Wed, 17 Jun 2026 05:40:11 +0200 Subject: [PATCH 048/116] bless batch (and remove duplicate test) --- .../assoc-type-projection-in-default-method.rs | 1 + ...ssociated-type-projection-alias-in-field.rs | 2 ++ .../associated-types/normalize-assoc-types.rs | 7 ++++--- .../ui/associated-types/ret-associated-type.rs | 2 ++ ...ait-bound-references-own-associated-type.rs | 1 + .../no-dropck-overflow-on-deep-nesting.rs | 9 ++++++--- tests/ui/issues/issue-22370.rs | 6 ------ tests/ui/issues/issue-22370.stderr | 18 ------------------ ...finite-instantiation-via-nested-closures.rs | 1 + ...te-instantiation-via-nested-closures.stderr | 6 +++--- .../where-clause-on-generic-type-alias.rs | 3 ++- .../fnonce-impl-on-unit-struct.rs | 1 + 12 files changed, 23 insertions(+), 34 deletions(-) delete mode 100644 tests/ui/issues/issue-22370.rs delete mode 100644 tests/ui/issues/issue-22370.stderr diff --git a/tests/ui/associated-types/assoc-type-projection-in-default-method.rs b/tests/ui/associated-types/assoc-type-projection-in-default-method.rs index befdf7ead06d2..1886d6384b412 100644 --- a/tests/ui/associated-types/assoc-type-projection-in-default-method.rs +++ b/tests/ui/associated-types/assoc-type-projection-in-default-method.rs @@ -1,3 +1,4 @@ +//! Regression test for . //@ run-pass trait DigitCollection: Sized { diff --git a/tests/ui/associated-types/associated-type-projection-alias-in-field.rs b/tests/ui/associated-types/associated-type-projection-alias-in-field.rs index b7c5c2a59327e..de7350b108831 100644 --- a/tests/ui/associated-types/associated-type-projection-alias-in-field.rs +++ b/tests/ui/associated-types/associated-type-projection-alias-in-field.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ check-pass #![allow(type_alias_bounds)] diff --git a/tests/ui/associated-types/normalize-assoc-types.rs b/tests/ui/associated-types/normalize-assoc-types.rs index 22da414650f85..c90fef9554af8 100644 --- a/tests/ui/associated-types/normalize-assoc-types.rs +++ b/tests/ui/associated-types/normalize-assoc-types.rs @@ -1,8 +1,9 @@ +//! Regression test for . +//! Test transitive analysis for associated types. Collected types +//! should be normalized and new obligations generated. + //@ run-pass #![allow(unused_imports)] -// Test transitive analysis for associated types. Collected types -// should be normalized and new obligations generated. - use std::borrow::{ToOwned, Cow}; diff --git a/tests/ui/associated-types/ret-associated-type.rs b/tests/ui/associated-types/ret-associated-type.rs index a1eb8ba14ca98..0da4dfbe73c80 100644 --- a/tests/ui/associated-types/ret-associated-type.rs +++ b/tests/ui/associated-types/ret-associated-type.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ run-pass use std::ops::Add; diff --git a/tests/ui/associated-types/supertrait-bound-references-own-associated-type.rs b/tests/ui/associated-types/supertrait-bound-references-own-associated-type.rs index 019c45dbadc8a..7d410fd4d6127 100644 --- a/tests/ui/associated-types/supertrait-bound-references-own-associated-type.rs +++ b/tests/ui/associated-types/supertrait-bound-references-own-associated-type.rs @@ -1,3 +1,4 @@ +//! Regression test for . //@ check-pass trait Expr: PartialEq { diff --git a/tests/ui/dropck/no-dropck-overflow-on-deep-nesting.rs b/tests/ui/dropck/no-dropck-overflow-on-deep-nesting.rs index c95bb9cc3bb99..6553374189a32 100644 --- a/tests/ui/dropck/no-dropck-overflow-on-deep-nesting.rs +++ b/tests/ui/dropck/no-dropck-overflow-on-deep-nesting.rs @@ -1,7 +1,10 @@ +//! Regression test for . +//! +//! This test is reduced from librustc_ast. It is just checking that we +//! can successfully deal with a "deep" structure, which the drop-check +//! was hitting a recursion limit on at one point. + //@ check-pass -// This test is reduced from librustc_ast. It is just checking that we -// can successfully deal with a "deep" structure, which the drop-check -// was hitting a recursion limit on at one point. #![allow(non_camel_case_types)] diff --git a/tests/ui/issues/issue-22370.rs b/tests/ui/issues/issue-22370.rs deleted file mode 100644 index bab0469c01193..0000000000000 --- a/tests/ui/issues/issue-22370.rs +++ /dev/null @@ -1,6 +0,0 @@ -trait A {} - -fn f(a: &dyn A) {} -//~^ ERROR E0393 - -fn main() {} diff --git a/tests/ui/issues/issue-22370.stderr b/tests/ui/issues/issue-22370.stderr deleted file mode 100644 index cd1580e844cad..0000000000000 --- a/tests/ui/issues/issue-22370.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0393]: the type parameter `T` must be explicitly specified - --> $DIR/issue-22370.rs:3:14 - | -LL | trait A {} - | --------------- type parameter `T` must be specified for this -LL | -LL | fn f(a: &dyn A) {} - | ^ - | - = note: because the parameter default references `Self`, the parameter must be specified on the trait object type -help: explicitly specify the type parameter - | -LL | fn f(a: &dyn A) {} - | +++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0393`. diff --git a/tests/ui/recursion/infinite-instantiation-via-nested-closures.rs b/tests/ui/recursion/infinite-instantiation-via-nested-closures.rs index be9304e5829f0..6961d9a4dfde8 100644 --- a/tests/ui/recursion/infinite-instantiation-via-nested-closures.rs +++ b/tests/ui/recursion/infinite-instantiation-via-nested-closures.rs @@ -1,3 +1,4 @@ +//! Regression test for . //@ build-fail #![allow(unused)] diff --git a/tests/ui/recursion/infinite-instantiation-via-nested-closures.stderr b/tests/ui/recursion/infinite-instantiation-via-nested-closures.stderr index 96f1794486838..c4171e23b5917 100644 --- a/tests/ui/recursion/infinite-instantiation-via-nested-closures.stderr +++ b/tests/ui/recursion/infinite-instantiation-via-nested-closures.stderr @@ -1,11 +1,11 @@ -error: reached the recursion limit while instantiating `A::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>` - --> $DIR/issue-22638.rs:54:9 +error: reached the recursion limit while instantiating `A::matches::<{closure@$DIR/infinite-instantiation-via-nested-closures.rs:43:23: 43:25}>` + --> $DIR/infinite-instantiation-via-nested-closures.rs:55:9 | LL | a.matches(f) | ^^^^^^^^^^^^ | note: `A::matches` defined here - --> $DIR/issue-22638.rs:13:5 + --> $DIR/infinite-instantiation-via-nested-closures.rs:14:5 | LL | pub fn matches(&self, f: &F) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/type-alias/where-clause-on-generic-type-alias.rs b/tests/ui/type-alias/where-clause-on-generic-type-alias.rs index a983fec05c865..9e306e1fdfac6 100644 --- a/tests/ui/type-alias/where-clause-on-generic-type-alias.rs +++ b/tests/ui/type-alias/where-clause-on-generic-type-alias.rs @@ -1,5 +1,6 @@ +//! Regression test for . + //@ check-pass -#![allow(dead_code)] #![allow(type_alias_bounds)] type Foo where T: Copy = Box; diff --git a/tests/ui/unboxed-closures/fnonce-impl-on-unit-struct.rs b/tests/ui/unboxed-closures/fnonce-impl-on-unit-struct.rs index 63d5e3b2ae6cb..bee2b91c6b430 100644 --- a/tests/ui/unboxed-closures/fnonce-impl-on-unit-struct.rs +++ b/tests/ui/unboxed-closures/fnonce-impl-on-unit-struct.rs @@ -1,3 +1,4 @@ +//! Regression test for . //@ check-pass #![feature(unboxed_closures, fn_traits)] From a7219132bd832ee861d4ccf7fc7beab974797ba9 Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 15 Jun 2026 22:10:21 +0200 Subject: [PATCH 049/116] move batch --- .../hashmap-send-requires-send-contents.rs} | 0 .../hashmap-send-requires-send-contents.stderr} | 0 .../issue-21922.rs => binop/add-ref-operand-method-lookup.rs} | 0 tests/ui/{issues/issue-21634.rs => binop/infer-rhs-type.rs} | 0 .../{issues/issue-22034.rs => cast/raw-ptr-to-dyn-fn-raw-ptr.rs} | 0 .../issue-22034.stderr => cast/raw-ptr-to-dyn-fn-raw-ptr.stderr} | 0 .../issue-22008.rs => match/match-str-proper-optimization.rs} | 0 .../nested-fn-call-shadowed-assoc-fn-variable.rs} | 0 .../issue-2150.rs => reachable/unreachable-ret-after-panic.rs} | 0 .../unreachable-ret-after-panic.stderr} | 0 .../issue-21546.rs => resolve/module-type-name-conflict.rs} | 0 .../module-type-name-conflict.stderr} | 0 .../ambiguous-trait-matching-distinct-lifetimes.rs} | 0 .../ambiguous-trait-matching-distinct-lifetimes.stderr} | 0 .../{issues/issue-21701.rs => typeck/call-non-fn-type-param.rs} | 0 .../issue-21701.stderr => typeck/call-non-fn-type-param.stderr} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-21763.rs => auto-traits/hashmap-send-requires-send-contents.rs} (100%) rename tests/ui/{issues/issue-21763.stderr => auto-traits/hashmap-send-requires-send-contents.stderr} (100%) rename tests/ui/{issues/issue-21922.rs => binop/add-ref-operand-method-lookup.rs} (100%) rename tests/ui/{issues/issue-21634.rs => binop/infer-rhs-type.rs} (100%) rename tests/ui/{issues/issue-22034.rs => cast/raw-ptr-to-dyn-fn-raw-ptr.rs} (100%) rename tests/ui/{issues/issue-22034.stderr => cast/raw-ptr-to-dyn-fn-raw-ptr.stderr} (100%) rename tests/ui/{issues/issue-22008.rs => match/match-str-proper-optimization.rs} (100%) rename tests/ui/{issues/issue-21622.rs => methods/nested-fn-call-shadowed-assoc-fn-variable.rs} (100%) rename tests/ui/{issues/issue-2150.rs => reachable/unreachable-ret-after-panic.rs} (100%) rename tests/ui/{issues/issue-2150.stderr => reachable/unreachable-ret-after-panic.stderr} (100%) rename tests/ui/{issues/issue-21546.rs => resolve/module-type-name-conflict.rs} (100%) rename tests/ui/{issues/issue-21546.stderr => resolve/module-type-name-conflict.stderr} (100%) rename tests/ui/{issues/issue-21974.rs => traits/ambiguous-trait-matching-distinct-lifetimes.rs} (100%) rename tests/ui/{issues/issue-21974.stderr => traits/ambiguous-trait-matching-distinct-lifetimes.stderr} (100%) rename tests/ui/{issues/issue-21701.rs => typeck/call-non-fn-type-param.rs} (100%) rename tests/ui/{issues/issue-21701.stderr => typeck/call-non-fn-type-param.stderr} (100%) diff --git a/tests/ui/issues/issue-21763.rs b/tests/ui/auto-traits/hashmap-send-requires-send-contents.rs similarity index 100% rename from tests/ui/issues/issue-21763.rs rename to tests/ui/auto-traits/hashmap-send-requires-send-contents.rs diff --git a/tests/ui/issues/issue-21763.stderr b/tests/ui/auto-traits/hashmap-send-requires-send-contents.stderr similarity index 100% rename from tests/ui/issues/issue-21763.stderr rename to tests/ui/auto-traits/hashmap-send-requires-send-contents.stderr diff --git a/tests/ui/issues/issue-21922.rs b/tests/ui/binop/add-ref-operand-method-lookup.rs similarity index 100% rename from tests/ui/issues/issue-21922.rs rename to tests/ui/binop/add-ref-operand-method-lookup.rs diff --git a/tests/ui/issues/issue-21634.rs b/tests/ui/binop/infer-rhs-type.rs similarity index 100% rename from tests/ui/issues/issue-21634.rs rename to tests/ui/binop/infer-rhs-type.rs diff --git a/tests/ui/issues/issue-22034.rs b/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.rs similarity index 100% rename from tests/ui/issues/issue-22034.rs rename to tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.rs diff --git a/tests/ui/issues/issue-22034.stderr b/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.stderr similarity index 100% rename from tests/ui/issues/issue-22034.stderr rename to tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.stderr diff --git a/tests/ui/issues/issue-22008.rs b/tests/ui/match/match-str-proper-optimization.rs similarity index 100% rename from tests/ui/issues/issue-22008.rs rename to tests/ui/match/match-str-proper-optimization.rs diff --git a/tests/ui/issues/issue-21622.rs b/tests/ui/methods/nested-fn-call-shadowed-assoc-fn-variable.rs similarity index 100% rename from tests/ui/issues/issue-21622.rs rename to tests/ui/methods/nested-fn-call-shadowed-assoc-fn-variable.rs diff --git a/tests/ui/issues/issue-2150.rs b/tests/ui/reachable/unreachable-ret-after-panic.rs similarity index 100% rename from tests/ui/issues/issue-2150.rs rename to tests/ui/reachable/unreachable-ret-after-panic.rs diff --git a/tests/ui/issues/issue-2150.stderr b/tests/ui/reachable/unreachable-ret-after-panic.stderr similarity index 100% rename from tests/ui/issues/issue-2150.stderr rename to tests/ui/reachable/unreachable-ret-after-panic.stderr diff --git a/tests/ui/issues/issue-21546.rs b/tests/ui/resolve/module-type-name-conflict.rs similarity index 100% rename from tests/ui/issues/issue-21546.rs rename to tests/ui/resolve/module-type-name-conflict.rs diff --git a/tests/ui/issues/issue-21546.stderr b/tests/ui/resolve/module-type-name-conflict.stderr similarity index 100% rename from tests/ui/issues/issue-21546.stderr rename to tests/ui/resolve/module-type-name-conflict.stderr diff --git a/tests/ui/issues/issue-21974.rs b/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.rs similarity index 100% rename from tests/ui/issues/issue-21974.rs rename to tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.rs diff --git a/tests/ui/issues/issue-21974.stderr b/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.stderr similarity index 100% rename from tests/ui/issues/issue-21974.stderr rename to tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.stderr diff --git a/tests/ui/issues/issue-21701.rs b/tests/ui/typeck/call-non-fn-type-param.rs similarity index 100% rename from tests/ui/issues/issue-21701.rs rename to tests/ui/typeck/call-non-fn-type-param.rs diff --git a/tests/ui/issues/issue-21701.stderr b/tests/ui/typeck/call-non-fn-type-param.stderr similarity index 100% rename from tests/ui/issues/issue-21701.stderr rename to tests/ui/typeck/call-non-fn-type-param.stderr From 05b0947f257042e1773f0cf338eb0d206432aed2 Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 15 Jun 2026 22:10:43 +0200 Subject: [PATCH 050/116] bless batch --- .../hashmap-send-requires-send-contents.rs | 3 ++- .../hashmap-send-requires-send-contents.stderr | 4 ++-- tests/ui/binop/add-ref-operand-method-lookup.rs | 7 +++++++ tests/ui/binop/infer-rhs-type.rs | 1 + tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.rs | 2 ++ tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.stderr | 2 +- tests/ui/match/match-str-proper-optimization.rs | 5 +++++ .../nested-fn-call-shadowed-assoc-fn-variable.rs | 2 ++ tests/ui/reachable/unreachable-ret-after-panic.rs | 2 ++ .../ui/reachable/unreachable-ret-after-panic.stderr | 4 ++-- tests/ui/resolve/module-type-name-conflict.rs | 5 ++++- tests/ui/resolve/module-type-name-conflict.stderr | 12 ++++++------ .../ambiguous-trait-matching-distinct-lifetimes.rs | 10 ++++++---- ...mbiguous-trait-matching-distinct-lifetimes.stderr | 8 ++++---- tests/ui/typeck/call-non-fn-type-param.rs | 2 ++ tests/ui/typeck/call-non-fn-type-param.stderr | 4 ++-- 16 files changed, 50 insertions(+), 23 deletions(-) diff --git a/tests/ui/auto-traits/hashmap-send-requires-send-contents.rs b/tests/ui/auto-traits/hashmap-send-requires-send-contents.rs index 5f236a25e9944..b543929642f3f 100644 --- a/tests/ui/auto-traits/hashmap-send-requires-send-contents.rs +++ b/tests/ui/auto-traits/hashmap-send-requires-send-contents.rs @@ -1,4 +1,5 @@ -// Regression test for HashMap only impl'ing Send/Sync if its contents do +//! Regression test for . +//! Test HashMap only impl Send/Sync if its contents do //@ normalize-stderr: "(?:[A-Za-z]:[/\\]|/).*[\\/]hashbrown\S+" -> "$$HASHBROWN_SRC_LOCATION" diff --git a/tests/ui/auto-traits/hashmap-send-requires-send-contents.stderr b/tests/ui/auto-traits/hashmap-send-requires-send-contents.stderr index 135b705eeeff2..db37db925b00a 100644 --- a/tests/ui/auto-traits/hashmap-send-requires-send-contents.stderr +++ b/tests/ui/auto-traits/hashmap-send-requires-send-contents.stderr @@ -1,5 +1,5 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely - --> $DIR/issue-21763.rs:11:11 + --> $DIR/hashmap-send-requires-send-contents.rs:12:11 | LL | foo::, Rc<()>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely @@ -12,7 +12,7 @@ note: required because it appears within the type `hashbrown::map::HashMap, Rc<()>>` --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL note: required by a bound in `foo` - --> $DIR/issue-21763.rs:8:11 + --> $DIR/hashmap-send-requires-send-contents.rs:9:11 | LL | fn foo() {} | ^^^^ required by this bound in `foo` diff --git a/tests/ui/binop/add-ref-operand-method-lookup.rs b/tests/ui/binop/add-ref-operand-method-lookup.rs index 6404ab8b7aa0f..b4573fc7658b6 100644 --- a/tests/ui/binop/add-ref-operand-method-lookup.rs +++ b/tests/ui/binop/add-ref-operand-method-lookup.rs @@ -1,3 +1,10 @@ +//! Regression test for . +//! +//! Ensure Add works with all value/reference operand combinations, +//! both via the + operator and ufcs. +//! +//! Originally method lookup failed only for x + &y. + //@ run-pass use std::ops::Add; fn show(z: i32) { diff --git a/tests/ui/binop/infer-rhs-type.rs b/tests/ui/binop/infer-rhs-type.rs index 475a33eca58ec..41ad829141c63 100644 --- a/tests/ui/binop/infer-rhs-type.rs +++ b/tests/ui/binop/infer-rhs-type.rs @@ -1,3 +1,4 @@ +//! Regression test for . //@ run-pass #[cfg(any(not(target_arch = "x86"), target_feature = "sse2"))] diff --git a/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.rs b/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.rs index 3631c2368fe82..6572140786d2e 100644 --- a/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.rs +++ b/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.rs @@ -1,3 +1,5 @@ +//! Regression test for . + fn main() { let ptr: *mut () = core::ptr::null_mut(); let _: &mut dyn Fn() = unsafe { diff --git a/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.stderr b/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.stderr index 68202085e77db..d0f0bcb201425 100644 --- a/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.stderr +++ b/tests/ui/cast/raw-ptr-to-dyn-fn-raw-ptr.stderr @@ -1,5 +1,5 @@ error[E0277]: expected a `Fn()` closure, found `()` - --> $DIR/issue-22034.rs:4:16 + --> $DIR/raw-ptr-to-dyn-fn-raw-ptr.rs:6:16 | LL | &mut *(ptr as *mut dyn Fn()) | ^^^ expected an `Fn()` closure, found `()` diff --git a/tests/ui/match/match-str-proper-optimization.rs b/tests/ui/match/match-str-proper-optimization.rs index b537ce8c2721c..79c56b22d0569 100644 --- a/tests/ui/match/match-str-proper-optimization.rs +++ b/tests/ui/match/match-str-proper-optimization.rs @@ -1,3 +1,8 @@ +//! Regression test for . +//! Ensure matching against `str` doesn't cause segfault when compiled +//! with `opt-level` >= 2. +// +//@ compile-flags: -C opt-level=2 //@ run-pass pub fn main() { let command = "a"; diff --git a/tests/ui/methods/nested-fn-call-shadowed-assoc-fn-variable.rs b/tests/ui/methods/nested-fn-call-shadowed-assoc-fn-variable.rs index 8dbc2c21ba951..65059cf38cd3c 100644 --- a/tests/ui/methods/nested-fn-call-shadowed-assoc-fn-variable.rs +++ b/tests/ui/methods/nested-fn-call-shadowed-assoc-fn-variable.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ check-pass #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/reachable/unreachable-ret-after-panic.rs b/tests/ui/reachable/unreachable-ret-after-panic.rs index baa1dde0fc2e8..db8673e5fd59b 100644 --- a/tests/ui/reachable/unreachable-ret-after-panic.rs +++ b/tests/ui/reachable/unreachable-ret-after-panic.rs @@ -1,3 +1,5 @@ +//! Regression test for . + #![deny(unreachable_code)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/tests/ui/reachable/unreachable-ret-after-panic.stderr b/tests/ui/reachable/unreachable-ret-after-panic.stderr index a9268646edfcb..7b73ddc723042 100644 --- a/tests/ui/reachable/unreachable-ret-after-panic.stderr +++ b/tests/ui/reachable/unreachable-ret-after-panic.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/issue-2150.rs:8:5 + --> $DIR/unreachable-ret-after-panic.rs:10:5 | LL | panic!(); | -------- any code following this expression is unreachable @@ -7,7 +7,7 @@ LL | for x in &v { i += 1; } | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here - --> $DIR/issue-2150.rs:1:9 + --> $DIR/unreachable-ret-after-panic.rs:3:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/resolve/module-type-name-conflict.rs b/tests/ui/resolve/module-type-name-conflict.rs index 9f3974b431470..b054fead6bc1f 100644 --- a/tests/ui/resolve/module-type-name-conflict.rs +++ b/tests/ui/resolve/module-type-name-conflict.rs @@ -1,4 +1,7 @@ -// Also works as a test for #14564 +//! Regression test for . +//! Ensure structs, enums and modules cannot share name in namespace. +//! +//! Also works as a test for . #[allow(non_snake_case)] mod Foo { } diff --git a/tests/ui/resolve/module-type-name-conflict.stderr b/tests/ui/resolve/module-type-name-conflict.stderr index 5fd06fc673361..fd5649cfc4512 100644 --- a/tests/ui/resolve/module-type-name-conflict.stderr +++ b/tests/ui/resolve/module-type-name-conflict.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-21546.rs:7:1 + --> $DIR/module-type-name-conflict.rs:10:1 | LL | mod Foo { } | ------- previous definition of the module `Foo` here @@ -10,7 +10,7 @@ LL | struct Foo; = note: `Foo` must be defined only once in the type namespace of this module error[E0428]: the name `Bar` is defined multiple times - --> $DIR/issue-21546.rs:14:1 + --> $DIR/module-type-name-conflict.rs:17:1 | LL | mod Bar { } | ------- previous definition of the module `Bar` here @@ -21,7 +21,7 @@ LL | struct Bar(i32); = note: `Bar` must be defined only once in the type namespace of this module error[E0428]: the name `Baz` is defined multiple times - --> $DIR/issue-21546.rs:22:1 + --> $DIR/module-type-name-conflict.rs:25:1 | LL | struct Baz(i32); | ---------------- previous definition of the type `Baz` here @@ -32,7 +32,7 @@ LL | mod Baz { } = note: `Baz` must be defined only once in the type namespace of this module error[E0428]: the name `Qux` is defined multiple times - --> $DIR/issue-21546.rs:30:1 + --> $DIR/module-type-name-conflict.rs:33:1 | LL | struct Qux { x: bool } | ---------- previous definition of the type `Qux` here @@ -43,7 +43,7 @@ LL | mod Qux { } = note: `Qux` must be defined only once in the type namespace of this module error[E0428]: the name `Quux` is defined multiple times - --> $DIR/issue-21546.rs:38:1 + --> $DIR/module-type-name-conflict.rs:41:1 | LL | struct Quux; | ------------ previous definition of the type `Quux` here @@ -54,7 +54,7 @@ LL | mod Quux { } = note: `Quux` must be defined only once in the type namespace of this module error[E0428]: the name `Corge` is defined multiple times - --> $DIR/issue-21546.rs:46:1 + --> $DIR/module-type-name-conflict.rs:49:1 | LL | enum Corge { A, B } | ---------- previous definition of the type `Corge` here diff --git a/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.rs b/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.rs index 24e92ce7b9177..d5cf73b42f561 100644 --- a/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.rs +++ b/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.rs @@ -1,7 +1,9 @@ -// Test that (for now) we report an ambiguity error here, because -// specific trait relationships are ignored for the purposes of trait -// matching. This behavior should likely be improved such that this -// test passes. See #21974 for more details. +//! . +//! +//! Test that (for now) we report an ambiguity error here, because +//! specific trait relationships are ignored for the purposes of trait +//! matching. This behavior should likely be improved such that this +//! test passes. trait Foo { fn foo(self); diff --git a/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.stderr b/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.stderr index cc9164e5621b8..d2d7df466512d 100644 --- a/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.stderr +++ b/tests/ui/traits/ambiguous-trait-matching-distinct-lifetimes.stderr @@ -1,11 +1,11 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo` - --> $DIR/issue-21974.rs:11:19 + --> $DIR/ambiguous-trait-matching-distinct-lifetimes.rs:13:19 | LL | where &'a T : Foo, | ^^^ | note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found - --> $DIR/issue-21974.rs:11:19 + --> $DIR/ambiguous-trait-matching-distinct-lifetimes.rs:13:19 | LL | where &'a T : Foo, | ^^^ @@ -13,13 +13,13 @@ LL | &'b T : Foo | ^^^ error[E0283]: type annotations needed: cannot satisfy `&T: Foo` - --> $DIR/issue-21974.rs:14:7 + --> $DIR/ambiguous-trait-matching-distinct-lifetimes.rs:16:7 | LL | x.foo(); | ^^^ | note: multiple `impl`s or `where` clauses satisfying `&T: Foo` found - --> $DIR/issue-21974.rs:11:19 + --> $DIR/ambiguous-trait-matching-distinct-lifetimes.rs:13:19 | LL | where &'a T : Foo, | ^^^ diff --git a/tests/ui/typeck/call-non-fn-type-param.rs b/tests/ui/typeck/call-non-fn-type-param.rs index bfa03c5e42f8d..993d585bd2185 100644 --- a/tests/ui/typeck/call-non-fn-type-param.rs +++ b/tests/ui/typeck/call-non-fn-type-param.rs @@ -1,3 +1,5 @@ +//! Regression test for . + fn foo(t: U) { let y = t(); //~^ ERROR: expected function, found `U` diff --git a/tests/ui/typeck/call-non-fn-type-param.stderr b/tests/ui/typeck/call-non-fn-type-param.stderr index 9f1fe7dde735a..f62b571a5d9ad 100644 --- a/tests/ui/typeck/call-non-fn-type-param.stderr +++ b/tests/ui/typeck/call-non-fn-type-param.stderr @@ -1,5 +1,5 @@ error[E0618]: expected function, found `U` - --> $DIR/issue-21701.rs:2:13 + --> $DIR/call-non-fn-type-param.rs:4:13 | LL | fn foo(t: U) { | - `t` has type `U` @@ -9,7 +9,7 @@ LL | let y = t(); | call expression requires function error[E0618]: expected function, found struct `Bar` - --> $DIR/issue-21701.rs:9:13 + --> $DIR/call-non-fn-type-param.rs:11:13 | LL | struct Bar; | ---------- struct `Bar` defined here From d7a883109c40693febe6c0bf26e2718393676054 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 12 Jun 2026 19:02:48 +0200 Subject: [PATCH 051/116] internal: decide not to use `'db` in `NavigationTarget.docs` --- src/tools/rust-analyzer/crates/ide/src/navigation_target.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index b8c14dc09f9a2..24031429db88f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -50,7 +50,6 @@ pub struct NavigationTarget { pub kind: Option, pub container_name: Option, pub description: Option, - // FIXME: Use the database lifetime here. pub docs: Option>, /// In addition to a `name` field, a `NavigationTarget` may also be aliased /// In such cases we want a `NavigationTarget` to be accessible by its alias From b1483e347cd1152851def06910486635dd381772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 17 Jun 2026 13:07:22 +0200 Subject: [PATCH 052/116] Update mingw-w64 C toolchain --- src/ci/scripts/install-mingw.sh | 4 ++-- src/doc/rustc/src/platform-support/windows-gnu.md | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 17bedaa7b8266..470ef4ffea433 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -6,8 +6,8 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -MINGW_ARCHIVE_32="i686-14.1.0-release-posix-dwarf-msvcrt-rt_v12-rev0.7z" -MINGW_ARCHIVE_64="x86_64-14.1.0-release-posix-seh-msvcrt-rt_v12-rev0.7z" +MINGW_ARCHIVE_32="i686-14.2.0-release-posix-dwarf-msvcrt-rt_v12-rev2.7z" +MINGW_ARCHIVE_64="x86_64-14.2.0-release-posix-seh-msvcrt-rt_v12-rev2.7z" LLVM_MINGW_ARCHIVE_AARCH64="llvm-mingw-20251104-ucrt-aarch64.zip" LLVM_MINGW_ARCHIVE_X86_64="llvm-mingw-20251104-ucrt-x86_64.zip" diff --git a/src/doc/rustc/src/platform-support/windows-gnu.md b/src/doc/rustc/src/platform-support/windows-gnu.md index a867ebcfe2539..d7aec5af21dec 100644 --- a/src/doc/rustc/src/platform-support/windows-gnu.md +++ b/src/doc/rustc/src/platform-support/windows-gnu.md @@ -26,6 +26,18 @@ They follow Windows calling convention for `extern "C"`. Like with any other Windows target, created binaries are in PE format. +### C toolchain + +The targets are built and tested using a reasonably modern C toolchain, and it should be considered as the oldest supported version: + +* GNU Binutils 2.44 +* GCC 14.2 +* mingw-w64 12.0.0 +* MSVCRT library as the default + +Using older tools (especially Binutils) may not work properly, due to the number of issues plaguing older versions of Binutils. +The supported toolchain versions are subject to change. + ## Building Rust programs Rust does ship a pre-compiled std library for those targets. From 07fa0eadcf07d76dabc8e156b2902f48165f4d64 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 17 Jun 2026 12:01:29 +0100 Subject: [PATCH 053/116] fix: Crash on static constants in array length positions We were missing a match case in the solver interner: `SolverDefId::StaticId` wasn't covered, so we hit the `unimplemented!()` base case. This occurred when coercing array lengths with statics, see the new test case. Fixes rust-lang/rust-analyzer#22600 AI disclosure: Written with help by Codex and GPT 5.5. --- .../crates/hir-ty/src/next_solver/interner.rs | 3 +++ .../crates/hir-ty/src/tests/regression/new_solver.rs | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index b466fe0f1810b..9875a915dcdda 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1128,6 +1128,9 @@ impl<'db> Interner for DbInterner<'db> { SolverDefId::ConstId(def_id) => { AliasTermKind::UnevaluatedConst { def_id: GeneralConstIdWrapper(def_id.into()) } } + SolverDefId::StaticId(def_id) => { + AliasTermKind::UnevaluatedConst { def_id: GeneralConstIdWrapper(def_id.into()) } + } SolverDefId::AnonConstId(def_id) => { AliasTermKind::UnevaluatedConst { def_id: GeneralConstIdWrapper(def_id.into()) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index c77b20f4b54c1..17127b2771d2e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -394,6 +394,16 @@ fn main() { ); } +#[test] +fn static_as_array_len_does_not_panic() { + check_no_mismatches( + r#" +static S: usize = 8; +const A: [u8; S] = [0; 8]; + "#, + ); +} + #[test] fn another_20654_case() { check_no_mismatches( From f6653135737dddff55b3db1fa90fef774dfe0d3b Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 18 Apr 2026 23:55:32 +0200 Subject: [PATCH 054/116] misc improvements --- .../rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs | 2 +- src/tools/rust-analyzer/crates/ide-completion/src/render.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 6b6dd549b34e0..2c2f7dbf67301 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -843,7 +843,7 @@ impl<'db> InferCtxt<'db> { GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind, span)) } - /// Like `fresh_args_for_item()`, but first uses the args from `first`. + /// Like [`Self::fresh_args_for_item`], but first uses the args from `first`. pub fn fill_rest_fresh_args( &self, span: Span, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index e48847c983b4e..7cb1eaa061f3c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -2372,7 +2372,7 @@ impl S { } fn foo(s: S) { s.$0 } "#, - CompletionItemKind::SymbolKind(SymbolKind::Method), + SymbolKind::Method, expect![[r#" [ CompletionItem { From 2e19915718905a341e712e36ebe823f58de39445 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 18 Apr 2026 23:55:32 +0200 Subject: [PATCH 055/116] add failing test --- .../ide-completion/src/tests/expression.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 57f067dc94768..4e18a3641c684 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -4179,3 +4179,32 @@ fn main() { "#]], ); } + +#[test] +fn no_await_on_error_type() { + check( + r#" +//- minicore: future +fn foo(t: T) { + let _ = t.$0; +} + "#, + expect![[r#" + kw await expr.await + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn if if expr {} + sn match match expr {} + sn not !expr + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + sn while while expr {} + "#]], + ); +} From 7e95dd2ae0014aa9ea6ed3792267119348af840a Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 29 May 2026 17:53:12 +0200 Subject: [PATCH 056/116] fix: return `false` from `implements_trait_unique` for error types --- src/tools/rust-analyzer/crates/hir-ty/src/traits.rs | 5 ++++- .../crates/ide-completion/src/tests/expression.rs | 1 - .../test_data/highlight_general.html | 12 ++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 4c76ae901da8c..3b5890e5e4fe1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -20,7 +20,7 @@ use hir_expand::name::Name; use intern::sym; use rustc_type_ir::{ TypeVisitableExt, TypingMode, - inherent::{BoundExistentialPredicates, IntoKind}, + inherent::{BoundExistentialPredicates, GenericArg as _, IntoKind, Ty as _}, }; use crate::{ @@ -153,6 +153,9 @@ pub fn implements_trait_unique_with_infcx<'db>( let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let args = create_args(&infcx); + if args.iter().filter_map(|it| it.as_type()).any(|ty| ty.is_ty_error()) { + return false; + } let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args); let obligation = Obligation::new(interner, ObligationCause::dummy(), env.param_env, trait_ref); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 4e18a3641c684..adf4dda18441f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -4190,7 +4190,6 @@ fn foo(t: T) { } "#, expect![[r#" - kw await expr.await sn box Box::new(expr) sn call function(expr) sn const const {} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index 1184739cc2589..2f2c7f251a703 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -128,9 +128,9 @@ let y = &mut x; let z = &y; - let Foo { x: z, y } = Foo { x: z, y }; + let Foo { x: z, y } = Foo { x: z, y }; - y; + y; let mut foo = Foo { x, y: x }; let foo2 = Foo { x, y: x }; @@ -143,7 +143,7 @@ copy.qux(); copy.baz(copy); - let a = |x| x; + let a = |x| x; let bar = Foo::baz; let baz = (-42,); @@ -173,13 +173,13 @@ } async fn learn_and_sing() { - let song = learn_song().await; - sing_song(song).await; + let song = learn_song().await; + sing_song(song).await; } async fn async_main() { let f1 = learn_and_sing(); - let f2 = dance(); + let f2 = dance(); futures::join!(f1, f2); } From 7d9bf81611f4949ad788019b154b45d638bd0c03 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 17 Jun 2026 16:09:04 +0100 Subject: [PATCH 057/116] internal: Don't rely on FxHashSet order Previously, SCIP generation would iterate over all the external symbols by calling `.difference()` on an FxHashSet and iterating over them. If any tokens had a moniker but no definition, the loop would terminate early. AFAICS this code is unreachable today (all the monikers also have definitions), but the code is clearly wrong. Ensure we process all tokens regardless of the order. --- src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index bca38ed82fdd5..d3acbb934d5bb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -237,7 +237,7 @@ impl flags::Scip { let token = si.tokens.get(id).unwrap(); let Some(definition) = token.definition else { - break; + continue; }; let file_id = definition.file_id; From faa57cdd9b779817ea287741fa6a2b3fbda5ccff Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 17 Jun 2026 13:02:12 +0300 Subject: [PATCH 058/116] Check for #[cfg]s in tail expression macros --- .../crates/hir-def/src/expr_store/lower.rs | 8 +++--- .../hir-def/src/expr_store/tests/body.rs | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index bbc3f5333a14f..a69755baf632c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2404,6 +2404,10 @@ impl<'db> ExprCollector<'db> { statements: &mut Vec, mac: ast::MacroExpr, ) -> Option { + if !self.check_cfg(&ast::Expr::MacroExpr(mac.clone())) { + return None; + } + let mac_call = mac.macro_call()?; let syntax_ptr = AstPtr::new(&ast::Expr::from(mac)); let macro_ptr = AstPtr::new(&mac_call); @@ -2447,10 +2451,6 @@ impl<'db> ExprCollector<'db> { } ast::Stmt::ExprStmt(stmt) => { let expr = stmt.expr(); - match &expr { - Some(expr) if !self.check_cfg(expr) => return, - _ => (), - } let has_semi = stmt.semicolon_token().is_some(); // Note that macro could be expanded to multiple statements if let Some(ast::Expr::MacroExpr(mac)) = expr { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs index e97718ca22c32..da412a620d0a7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs @@ -688,3 +688,31 @@ fn foo() { }"#]], ); } + +#[test] +fn foo() { + pretty_print( + r#" +macro_rules! foo { + () => { + 1 + }; +} + +fn foo() -> i64 { + #[cfg(true)] + { + 5 + } + #[cfg(false)] + foo!() +} + "#, + expect![[r#" + fn foo() { + { + 5 + } + }"#]], + ); +} From d4bea3797042dd8cc669ba01bd7ebe1403a9e077 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 16 Jun 2026 23:08:17 +0200 Subject: [PATCH 059/116] Expand network address parser benchmark suite --- library/coretests/benches/net/addr_parser.rs | 176 ++++++++++++++++--- 1 file changed, 155 insertions(+), 21 deletions(-) diff --git a/library/coretests/benches/net/addr_parser.rs b/library/coretests/benches/net/addr_parser.rs index bbf2ea3eb9796..d44ea98bfcbec 100644 --- a/library/coretests/benches/net/addr_parser.rs +++ b/library/coretests/benches/net/addr_parser.rs @@ -3,76 +3,210 @@ use core::str::FromStr; use test::{Bencher, black_box}; -const IPV4_STR: &str = "192.168.0.1"; -const IPV4_STR_PORT: &str = "192.168.0.1:8080"; - -const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; -const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; -const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; -const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; -const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080"; +const IPV4: &[&str] = &[ + "192.168.0.1", + "8.8.8.8", + "127.0.0.1", + "255.255.255.255", + "0.0.0.0", + "10.0.0.1", + "203.0.113.42", + "172.16.254.1", + "100.64.0.1", + "1.2.3.4", +]; + +const IPV4_PORT: &[&str] = &[ + "192.168.0.1:8080", + "8.8.8.8:53", + "127.0.0.1:65535", + "255.255.255.255:1", + "0.0.0.0:80", + "10.0.0.1:443", + "203.0.113.42:22", + "172.16.254.1:3306", + "100.64.0.1:8443", + "1.2.3.4:0", +]; + +const IPV6_FULL: &[&str] = &[ + "2001:db8:0:0:0:0:c0a8:1", + "2001:db8:85a3:8d3:1319:8a2e:370:7348", + "fe80:0:0:0:0:0:0:1", + "ff02:0:0:0:0:0:0:101", + "2001:4860:4860:0:0:0:0:8888", + "2606:4700:4700:0:0:0:0:1111", + "fd00:0:0:0:0:0:0:1", + "fec0:0:0:0:0:0:0:abcd", + "1:2:3:4:5:6:7:8", + "abcd:ef01:2345:6789:abcd:ef01:2345:6789", +]; + +const IPV6_COMPRESS: &[&str] = &[ + "2001:db8::c0a8:1", + "::1", + "fe80::1", + "2001:db8::", + "ff02::1:2", + "64:ff9b::", + "::", + "2001:4860:4860::8888", + "2606:4700:4700::1111", + "fe80::1ff:fe23:4567:890a", +]; + +const IPV6_V4: &[&str] = &[ + "2001:db8::192.168.0.1", + "::ffff:192.168.0.1", + "64:ff9b::192.0.2.33", + "::ffff:8.8.8.8", + "::192.168.0.1", + "::ffff:255.255.255.255", + "2001:db8:0:0:0:0:192.168.0.1", + "64:ff9b::10.0.0.1", + "::ffff:1.2.3.4", + "::ffff:127.0.0.1", +]; + +const IPV6_PORT: &[&str] = &[ + "[2001:db8::c0a8:1]:8080", + "[::1]:443", + "[fe80::1]:53", + "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:22", + "[::]:80", + "[2001:4860:4860::8888]:443", + "[2606:4700:4700::1111]:53", + "[fe80::1ff:fe23:4567:890a]:8080", + "[64:ff9b::192.0.2.33]:443", + "[::ffff:8.8.8.8]:53", +]; + +const IPV6_PORT_SCOPE_ID: &[&str] = &[ + "[2001:db8::c0a8:1%1337]:8080", + "[fe80::1%1]:53", + "[fe80::1%999999]:443", + "[fe80::1%0]:80", + "[fe80::1ff:fe23:4567:890a%2]:8080", + "[::1%1]:443", + "[fe80::abcd%15]:22", + "[ff02::1%42]:5353", + "[fe80::1%4294967295]:443", + "[2001:db8::1%100]:8080", +]; #[bench] fn bench_parse_ipv4(b: &mut Bencher) { - b.iter(|| Ipv4Addr::from_str(black_box(IPV4_STR))); + b.iter(|| { + for s in IPV4 { + let _ = black_box(Ipv4Addr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_ipv6_full(b: &mut Bencher) { - b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_FULL))); + b.iter(|| { + for s in IPV6_FULL { + let _ = black_box(Ipv6Addr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_ipv6_compress(b: &mut Bencher) { - b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_COMPRESS))); + b.iter(|| { + for s in IPV6_COMPRESS { + let _ = black_box(Ipv6Addr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_ipv6_v4(b: &mut Bencher) { - b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_V4))); + b.iter(|| { + for s in IPV6_V4 { + let _ = black_box(Ipv6Addr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_ipaddr_v4(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV4_STR))); + b.iter(|| { + for s in IPV4 { + let _ = black_box(IpAddr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_ipaddr_v6_full(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV6_STR_FULL))); + b.iter(|| { + for s in IPV6_FULL { + let _ = black_box(IpAddr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_ipaddr_v6_compress(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV6_STR_COMPRESS))); + b.iter(|| { + for s in IPV6_COMPRESS { + let _ = black_box(IpAddr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_ipaddr_v6_v4(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV6_STR_V4))); + b.iter(|| { + for s in IPV6_V4 { + let _ = black_box(IpAddr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_socket_v4(b: &mut Bencher) { - b.iter(|| SocketAddrV4::from_str(black_box(IPV4_STR_PORT))); + b.iter(|| { + for s in IPV4_PORT { + let _ = black_box(SocketAddrV4::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_socket_v6(b: &mut Bencher) { - b.iter(|| SocketAddrV6::from_str(black_box(IPV6_STR_PORT))); + b.iter(|| { + for s in IPV6_PORT { + let _ = black_box(SocketAddrV6::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_socket_v6_scope_id(b: &mut Bencher) { - b.iter(|| SocketAddrV6::from_str(black_box(IPV6_STR_PORT_SCOPE_ID))); + b.iter(|| { + for s in IPV6_PORT_SCOPE_ID { + let _ = black_box(SocketAddrV6::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_socketaddr_v4(b: &mut Bencher) { - b.iter(|| SocketAddr::from_str(black_box(IPV4_STR_PORT))); + b.iter(|| { + for s in IPV4_PORT { + let _ = black_box(SocketAddr::from_str(black_box(s))); + } + }); } #[bench] fn bench_parse_socketaddr_v6(b: &mut Bencher) { - b.iter(|| SocketAddr::from_str(black_box(IPV6_STR_PORT))); + b.iter(|| { + for s in IPV6_PORT { + let _ = black_box(SocketAddr::from_str(black_box(s))); + } + }); } From 3f32f5112b0b4fa30797667f522721aad6c1fcd2 Mon Sep 17 00:00:00 2001 From: zedddie Date: Thu, 18 Jun 2026 04:15:44 +0200 Subject: [PATCH 060/116] move batch --- .../issue-23354-2.rs => array-slice-vec/eval-array-expr.rs} | 0 .../issue-23354.rs => array-slice-vec/eval-empty-array-expr.rs} | 0 .../associated-type-unconstrained-lifetime.rs} | 0 .../associated-type-unconstrained-lifetime.stderr} | 0 .../dyn-any-to-fn-with-missing-generics.rs} | 0 .../dyn-any-to-fn-with-missing-generics.stderr} | 0 tests/ui/{issues/issue-23261.rs => dst/match-dst-struct.rs} | 0 .../leak-check/trait-object-assoc-type-bound-unsatisfied.rs} | 0 .../leak-check/trait-object-assoc-type-bound-unsatisfied.stderr} | 0 .../issue-23041.rs => inference/downcast-fn-ptr-placeholder.rs} | 0 .../downcast-fn-ptr-placeholder.stderr} | 0 .../trait-bound-not-parsed-as-matcher.rs} | 0 .../issue-23311.rs => pattern/match-array-against-slice.rs} | 0 .../match-boxed-fn-entry-type-inference.rs} | 0 .../{issues/issue-22874.rs => unsized/unsized-slice-element.rs} | 0 .../issue-22874.stderr => unsized/unsized-slice-element.stderr} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-23354-2.rs => array-slice-vec/eval-array-expr.rs} (100%) rename tests/ui/{issues/issue-23354.rs => array-slice-vec/eval-empty-array-expr.rs} (100%) rename tests/ui/{issues/issue-22886.rs => associated-types/associated-type-unconstrained-lifetime.rs} (100%) rename tests/ui/{issues/issue-22886.stderr => associated-types/associated-type-unconstrained-lifetime.stderr} (100%) rename tests/ui/{issues/issue-23024.rs => cast/dyn-any-to-fn-with-missing-generics.rs} (100%) rename tests/ui/{issues/issue-23024.stderr => cast/dyn-any-to-fn-with-missing-generics.stderr} (100%) rename tests/ui/{issues/issue-23261.rs => dst/match-dst-struct.rs} (100%) rename tests/ui/{issues/issue-22872.rs => higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.rs} (100%) rename tests/ui/{issues/issue-22872.stderr => higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.stderr} (100%) rename tests/ui/{issues/issue-23041.rs => inference/downcast-fn-ptr-placeholder.rs} (100%) rename tests/ui/{issues/issue-23041.stderr => inference/downcast-fn-ptr-placeholder.stderr} (100%) rename tests/ui/{issues/issue-22814.rs => macros/trait-bound-not-parsed-as-matcher.rs} (100%) rename tests/ui/{issues/issue-23311.rs => pattern/match-array-against-slice.rs} (100%) rename tests/ui/{issues/issue-22781.rs => typeck/match-boxed-fn-entry-type-inference.rs} (100%) rename tests/ui/{issues/issue-22874.rs => unsized/unsized-slice-element.rs} (100%) rename tests/ui/{issues/issue-22874.stderr => unsized/unsized-slice-element.stderr} (100%) diff --git a/tests/ui/issues/issue-23354-2.rs b/tests/ui/array-slice-vec/eval-array-expr.rs similarity index 100% rename from tests/ui/issues/issue-23354-2.rs rename to tests/ui/array-slice-vec/eval-array-expr.rs diff --git a/tests/ui/issues/issue-23354.rs b/tests/ui/array-slice-vec/eval-empty-array-expr.rs similarity index 100% rename from tests/ui/issues/issue-23354.rs rename to tests/ui/array-slice-vec/eval-empty-array-expr.rs diff --git a/tests/ui/issues/issue-22886.rs b/tests/ui/associated-types/associated-type-unconstrained-lifetime.rs similarity index 100% rename from tests/ui/issues/issue-22886.rs rename to tests/ui/associated-types/associated-type-unconstrained-lifetime.rs diff --git a/tests/ui/issues/issue-22886.stderr b/tests/ui/associated-types/associated-type-unconstrained-lifetime.stderr similarity index 100% rename from tests/ui/issues/issue-22886.stderr rename to tests/ui/associated-types/associated-type-unconstrained-lifetime.stderr diff --git a/tests/ui/issues/issue-23024.rs b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.rs similarity index 100% rename from tests/ui/issues/issue-23024.rs rename to tests/ui/cast/dyn-any-to-fn-with-missing-generics.rs diff --git a/tests/ui/issues/issue-23024.stderr b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr similarity index 100% rename from tests/ui/issues/issue-23024.stderr rename to tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr diff --git a/tests/ui/issues/issue-23261.rs b/tests/ui/dst/match-dst-struct.rs similarity index 100% rename from tests/ui/issues/issue-23261.rs rename to tests/ui/dst/match-dst-struct.rs diff --git a/tests/ui/issues/issue-22872.rs b/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.rs similarity index 100% rename from tests/ui/issues/issue-22872.rs rename to tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.rs diff --git a/tests/ui/issues/issue-22872.stderr b/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.stderr similarity index 100% rename from tests/ui/issues/issue-22872.stderr rename to tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.stderr diff --git a/tests/ui/issues/issue-23041.rs b/tests/ui/inference/downcast-fn-ptr-placeholder.rs similarity index 100% rename from tests/ui/issues/issue-23041.rs rename to tests/ui/inference/downcast-fn-ptr-placeholder.rs diff --git a/tests/ui/issues/issue-23041.stderr b/tests/ui/inference/downcast-fn-ptr-placeholder.stderr similarity index 100% rename from tests/ui/issues/issue-23041.stderr rename to tests/ui/inference/downcast-fn-ptr-placeholder.stderr diff --git a/tests/ui/issues/issue-22814.rs b/tests/ui/macros/trait-bound-not-parsed-as-matcher.rs similarity index 100% rename from tests/ui/issues/issue-22814.rs rename to tests/ui/macros/trait-bound-not-parsed-as-matcher.rs diff --git a/tests/ui/issues/issue-23311.rs b/tests/ui/pattern/match-array-against-slice.rs similarity index 100% rename from tests/ui/issues/issue-23311.rs rename to tests/ui/pattern/match-array-against-slice.rs diff --git a/tests/ui/issues/issue-22781.rs b/tests/ui/typeck/match-boxed-fn-entry-type-inference.rs similarity index 100% rename from tests/ui/issues/issue-22781.rs rename to tests/ui/typeck/match-boxed-fn-entry-type-inference.rs diff --git a/tests/ui/issues/issue-22874.rs b/tests/ui/unsized/unsized-slice-element.rs similarity index 100% rename from tests/ui/issues/issue-22874.rs rename to tests/ui/unsized/unsized-slice-element.rs diff --git a/tests/ui/issues/issue-22874.stderr b/tests/ui/unsized/unsized-slice-element.stderr similarity index 100% rename from tests/ui/issues/issue-22874.stderr rename to tests/ui/unsized/unsized-slice-element.stderr From ed1dd8831e3e600abab62542ce12e0f3e7f0dee8 Mon Sep 17 00:00:00 2001 From: zedddie Date: Thu, 18 Jun 2026 04:27:11 +0200 Subject: [PATCH 061/116] bless batch --- tests/ui/array-slice-vec/eval-array-expr.rs | 5 ++++- tests/ui/array-slice-vec/eval-empty-array-expr.rs | 2 ++ .../associated-type-unconstrained-lifetime.rs | 13 ++++++++++++- .../associated-type-unconstrained-lifetime.stderr | 2 +- .../ui/cast/dyn-any-to-fn-with-missing-generics.rs | 1 + .../cast/dyn-any-to-fn-with-missing-generics.stderr | 4 ++-- tests/ui/dst/match-dst-struct.rs | 3 ++- .../trait-object-assoc-type-bound-unsatisfied.rs | 2 ++ ...trait-object-assoc-type-bound-unsatisfied.stderr | 4 ++-- tests/ui/inference/downcast-fn-ptr-placeholder.rs | 3 +++ .../ui/inference/downcast-fn-ptr-placeholder.stderr | 2 +- .../ui/macros/trait-bound-not-parsed-as-matcher.rs | 2 ++ tests/ui/pattern/match-array-against-slice.rs | 4 ++-- .../typeck/match-boxed-fn-entry-type-inference.rs | 2 ++ tests/ui/unsized/unsized-slice-element.rs | 2 ++ tests/ui/unsized/unsized-slice-element.stderr | 4 ++-- 16 files changed, 42 insertions(+), 13 deletions(-) diff --git a/tests/ui/array-slice-vec/eval-array-expr.rs b/tests/ui/array-slice-vec/eval-array-expr.rs index a296477215ed1..1238ffe696e96 100644 --- a/tests/ui/array-slice-vec/eval-array-expr.rs +++ b/tests/ui/array-slice-vec/eval-array-expr.rs @@ -1,9 +1,12 @@ +//! Regression test for . +//! Check expr in [expr; N] is always being evaluated. +//! +//! This used to trigger an LLVM assertion during compilation //@ run-fail //@ error-pattern:panic evaluated //@ needs-subprocess #[allow(unused_variables)] fn main() { - // This used to trigger an LLVM assertion during compilation let x = [panic!("panic evaluated"); 2]; } diff --git a/tests/ui/array-slice-vec/eval-empty-array-expr.rs b/tests/ui/array-slice-vec/eval-empty-array-expr.rs index eff5f3d27147a..92e1c689436ab 100644 --- a/tests/ui/array-slice-vec/eval-empty-array-expr.rs +++ b/tests/ui/array-slice-vec/eval-empty-array-expr.rs @@ -1,3 +1,5 @@ +//! Regression test for . +//! Check expr in [expr; N] is always being evaluated. //@ run-fail //@ error-pattern:panic evaluated //@ needs-subprocess diff --git a/tests/ui/associated-types/associated-type-unconstrained-lifetime.rs b/tests/ui/associated-types/associated-type-unconstrained-lifetime.rs index f8b576e094d8c..a4b278392b6d6 100644 --- a/tests/ui/associated-types/associated-type-unconstrained-lifetime.rs +++ b/tests/ui/associated-types/associated-type-unconstrained-lifetime.rs @@ -1,4 +1,15 @@ -// Regression test for #22886. +//! Regression test for . +//! Test that associated type's inner state cannot be observed past +//! borrow end via saved reference. +//! +//! This was possible as trait implementation with unconstrained lifetime +//! allowed to use any lifetime for associated type, which introduced +//! soundness holes. +//! +//! Fixed by prohibiting use of unconstrained lifetimes on associated types +//! in . +//! +//! Related . fn crash_please() { let mut iter = Newtype(Some(Box::new(0))); diff --git a/tests/ui/associated-types/associated-type-unconstrained-lifetime.stderr b/tests/ui/associated-types/associated-type-unconstrained-lifetime.stderr index aebbdf8a2ec12..108465bf6f932 100644 --- a/tests/ui/associated-types/associated-type-unconstrained-lifetime.stderr +++ b/tests/ui/associated-types/associated-type-unconstrained-lifetime.stderr @@ -1,5 +1,5 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-22886.rs:13:6 + --> $DIR/associated-type-unconstrained-lifetime.rs:24:6 | LL | impl<'a> Iterator for Newtype { | ^^ unconstrained lifetime parameter diff --git a/tests/ui/cast/dyn-any-to-fn-with-missing-generics.rs b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.rs index 1b072dd7b69c0..504fe096c4204 100644 --- a/tests/ui/cast/dyn-any-to-fn-with-missing-generics.rs +++ b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.rs @@ -1,3 +1,4 @@ +//! Regression test for . use std::any::Any; fn main() diff --git a/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr index 51db0414f3a39..53aa609321431 100644 --- a/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr +++ b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr @@ -1,5 +1,5 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change - --> $DIR/issue-23024.rs:8:39 + --> $DIR/dyn-any-to-fn-with-missing-generics.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); | ^^ help: use parenthetical notation instead: `Fn() -> ()` @@ -9,7 +9,7 @@ LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0107]: missing generics for trait `Fn` - --> $DIR/issue-23024.rs:8:39 + --> $DIR/dyn-any-to-fn-with-missing-generics.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); | ^^ expected 1 generic argument diff --git a/tests/ui/dst/match-dst-struct.rs b/tests/ui/dst/match-dst-struct.rs index 69f141e8bf870..1c3fca77c19b7 100644 --- a/tests/ui/dst/match-dst-struct.rs +++ b/tests/ui/dst/match-dst-struct.rs @@ -1,5 +1,6 @@ +//! Regression test for . +//! Matching on a DST struct should not trigger an LLVM assertion. //@ run-pass -// Matching on a DST struct should not trigger an LLVM assertion. struct Foo { a: i32, diff --git a/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.rs b/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.rs index 5db2891e65e75..a171e6cdee453 100644 --- a/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.rs +++ b/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.rs @@ -1,3 +1,5 @@ +//! Regression test for . + trait Wrap<'b> { fn foo(&'b mut self); } diff --git a/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.stderr b/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.stderr index 6ff710b113325..79ee006579e0b 100644 --- a/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.stderr +++ b/tests/ui/higher-ranked/leak-check/trait-object-assoc-type-bound-unsatisfied.stderr @@ -1,12 +1,12 @@ error[E0277]: `

>::Item` is not an iterator - --> $DIR/issue-22872.rs:20:40 + --> $DIR/trait-object-assoc-type-bound-unsatisfied.rs:22:40 | LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

>::Item` is not an iterator | = help: the trait `Iterator` is not implemented for `

>::Item` note: required for `Wrapper

` to implement `for<'b> Wrap<'b>` - --> $DIR/issue-22872.rs:7:13 + --> $DIR/trait-object-assoc-type-bound-unsatisfied.rs:9:13 | LL | impl<'b, P> Wrap<'b> for Wrapper

| ^^^^^^^^ ^^^^^^^^^^ diff --git a/tests/ui/inference/downcast-fn-ptr-placeholder.rs b/tests/ui/inference/downcast-fn-ptr-placeholder.rs index a1371521a0aa0..3b2d2c2857f9d 100644 --- a/tests/ui/inference/downcast-fn-ptr-placeholder.rs +++ b/tests/ui/inference/downcast-fn-ptr-placeholder.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Previously ICEd with cat_expr error, fixed by delaying bug. + use std::any::Any; fn main() { diff --git a/tests/ui/inference/downcast-fn-ptr-placeholder.stderr b/tests/ui/inference/downcast-fn-ptr-placeholder.stderr index b348a8695f6f2..0d1801ac644df 100644 --- a/tests/ui/inference/downcast-fn-ptr-placeholder.stderr +++ b/tests/ui/inference/downcast-fn-ptr-placeholder.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-23041.rs:6:22 + --> $DIR/downcast-fn-ptr-placeholder.rs:9:22 | LL | b.downcast_ref::_>(); | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the method `downcast_ref` diff --git a/tests/ui/macros/trait-bound-not-parsed-as-matcher.rs b/tests/ui/macros/trait-bound-not-parsed-as-matcher.rs index 95ddeb15b57dd..0230df4aeb30c 100644 --- a/tests/ui/macros/trait-bound-not-parsed-as-matcher.rs +++ b/tests/ui/macros/trait-bound-not-parsed-as-matcher.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ check-pass trait Test {} diff --git a/tests/ui/pattern/match-array-against-slice.rs b/tests/ui/pattern/match-array-against-slice.rs index e827fa1670fb3..a396e2adab822 100644 --- a/tests/ui/pattern/match-array-against-slice.rs +++ b/tests/ui/pattern/match-array-against-slice.rs @@ -1,7 +1,7 @@ +//! Regression test for . +//! Test that we do not ICE when pattern matching an array against a slice. //@ run-pass -// Test that we do not ICE when pattern matching an array against a slice. - fn main() { match "foo".as_bytes() { b"food" => (), diff --git a/tests/ui/typeck/match-boxed-fn-entry-type-inference.rs b/tests/ui/typeck/match-boxed-fn-entry-type-inference.rs index 36314afd6222d..8d2b1603a6fa6 100644 --- a/tests/ui/typeck/match-boxed-fn-entry-type-inference.rs +++ b/tests/ui/typeck/match-boxed-fn-entry-type-inference.rs @@ -1,3 +1,5 @@ +//! Regression test for . + //@ check-pass #![allow(unused_variables)] use std::collections::HashMap; diff --git a/tests/ui/unsized/unsized-slice-element.rs b/tests/ui/unsized/unsized-slice-element.rs index c4500aacb6184..8ac81463be7e4 100644 --- a/tests/ui/unsized/unsized-slice-element.rs +++ b/tests/ui/unsized/unsized-slice-element.rs @@ -1,3 +1,5 @@ +//! Regression test for . + struct Table { rows: [[String]], //~^ ERROR the size for values of type diff --git a/tests/ui/unsized/unsized-slice-element.stderr b/tests/ui/unsized/unsized-slice-element.stderr index 7d5b601ed494f..1707e5f7a2aa5 100644 --- a/tests/ui/unsized/unsized-slice-element.stderr +++ b/tests/ui/unsized/unsized-slice-element.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[String]` cannot be known at compilation time - --> $DIR/issue-22874.rs:2:11 + --> $DIR/unsized-slice-element.rs:4:11 | LL | rows: [[String]], | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -8,7 +8,7 @@ LL | rows: [[String]], = note: slice and array elements must have `Sized` type error[E0277]: the size for values of type `[String]` cannot be known at compilation time - --> $DIR/issue-22874.rs:7:6 + --> $DIR/unsized-slice-element.rs:9:6 | LL | &table.rows[0] | ^^^^^^^^^^ doesn't have a size known at compile-time From b1403bc9f6cf3c0218c74ee8cbbb1e945bb52463 Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Fri, 5 Jun 2026 13:59:31 +0100 Subject: [PATCH 062/116] Move derive tests out of tests/ui/issues --- .../{issues/issue-28561.rs => derives/derive-compound-arities.rs} | 0 .../derive-error-identifies-unsafe-trait-name.rs} | 0 .../derive-error-identifies-unsafe-trait-name.stderr} | 0 .../derived-trait-requires-field-impl.rs} | 0 .../derived-trait-requires-field-impl.stderr} | 0 .../no-ice-on-derived-copy-with-associated-type-field.rs} | 0 .../no-ice-on-path-style-derive-macro.rs} | 0 .../no-ice-on-path-style-derive-macro.stderr} | 0 .../no-spurious-unused-variable-warning-on-derive-hash.rs} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-28561.rs => derives/derive-compound-arities.rs} (100%) rename tests/ui/{issues/issue-33571.rs => derives/derive-error-identifies-unsafe-trait-name.rs} (100%) rename tests/ui/{issues/issue-33571.stderr => derives/derive-error-identifies-unsafe-trait-name.stderr} (100%) rename tests/ui/{issues/issue-27340.rs => derives/derived-trait-requires-field-impl.rs} (100%) rename tests/ui/{issues/issue-27340.stderr => derives/derived-trait-requires-field-impl.stderr} (100%) rename tests/ui/{issues/issue-32324.rs => derives/no-ice-on-derived-copy-with-associated-type-field.rs} (100%) rename tests/ui/{issues/issue-46101.rs => derives/no-ice-on-path-style-derive-macro.rs} (100%) rename tests/ui/{issues/issue-46101.stderr => derives/no-ice-on-path-style-derive-macro.stderr} (100%) rename tests/ui/{issues/issue-32292.rs => derives/no-spurious-unused-variable-warning-on-derive-hash.rs} (100%) diff --git a/tests/ui/issues/issue-28561.rs b/tests/ui/derives/derive-compound-arities.rs similarity index 100% rename from tests/ui/issues/issue-28561.rs rename to tests/ui/derives/derive-compound-arities.rs diff --git a/tests/ui/issues/issue-33571.rs b/tests/ui/derives/derive-error-identifies-unsafe-trait-name.rs similarity index 100% rename from tests/ui/issues/issue-33571.rs rename to tests/ui/derives/derive-error-identifies-unsafe-trait-name.rs diff --git a/tests/ui/issues/issue-33571.stderr b/tests/ui/derives/derive-error-identifies-unsafe-trait-name.stderr similarity index 100% rename from tests/ui/issues/issue-33571.stderr rename to tests/ui/derives/derive-error-identifies-unsafe-trait-name.stderr diff --git a/tests/ui/issues/issue-27340.rs b/tests/ui/derives/derived-trait-requires-field-impl.rs similarity index 100% rename from tests/ui/issues/issue-27340.rs rename to tests/ui/derives/derived-trait-requires-field-impl.rs diff --git a/tests/ui/issues/issue-27340.stderr b/tests/ui/derives/derived-trait-requires-field-impl.stderr similarity index 100% rename from tests/ui/issues/issue-27340.stderr rename to tests/ui/derives/derived-trait-requires-field-impl.stderr diff --git a/tests/ui/issues/issue-32324.rs b/tests/ui/derives/no-ice-on-derived-copy-with-associated-type-field.rs similarity index 100% rename from tests/ui/issues/issue-32324.rs rename to tests/ui/derives/no-ice-on-derived-copy-with-associated-type-field.rs diff --git a/tests/ui/issues/issue-46101.rs b/tests/ui/derives/no-ice-on-path-style-derive-macro.rs similarity index 100% rename from tests/ui/issues/issue-46101.rs rename to tests/ui/derives/no-ice-on-path-style-derive-macro.rs diff --git a/tests/ui/issues/issue-46101.stderr b/tests/ui/derives/no-ice-on-path-style-derive-macro.stderr similarity index 100% rename from tests/ui/issues/issue-46101.stderr rename to tests/ui/derives/no-ice-on-path-style-derive-macro.stderr diff --git a/tests/ui/issues/issue-32292.rs b/tests/ui/derives/no-spurious-unused-variable-warning-on-derive-hash.rs similarity index 100% rename from tests/ui/issues/issue-32292.rs rename to tests/ui/derives/no-spurious-unused-variable-warning-on-derive-hash.rs From 68f9f5ac8143a2dbce8872d2f4d509a66fa8551c Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Fri, 5 Jun 2026 14:52:29 +0100 Subject: [PATCH 063/116] add issue links and bless --- tests/ui/derives/derive-compound-arities.rs | 1 + .../derives/derive-error-identifies-unsafe-trait-name.rs | 1 + .../derive-error-identifies-unsafe-trait-name.stderr | 8 ++++---- tests/ui/derives/derived-trait-requires-field-impl.rs | 1 + tests/ui/derives/derived-trait-requires-field-impl.stderr | 4 ++-- tests/ui/derives/hash-on-compound-types.rs | 3 +-- .../no-ice-on-derived-copy-with-associated-type-field.rs | 1 + tests/ui/derives/no-ice-on-path-style-derive-macro.rs | 1 + tests/ui/derives/no-ice-on-path-style-derive-macro.stderr | 4 ++-- .../no-spurious-unused-variable-warning-on-derive-hash.rs | 1 + 10 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/ui/derives/derive-compound-arities.rs b/tests/ui/derives/derive-compound-arities.rs index 642b2193a4f9b..704d6747f7e07 100644 --- a/tests/ui/derives/derive-compound-arities.rs +++ b/tests/ui/derives/derive-compound-arities.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/28561 //@ check-pass #[derive(Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Clone, Copy)] struct Array { diff --git a/tests/ui/derives/derive-error-identifies-unsafe-trait-name.rs b/tests/ui/derives/derive-error-identifies-unsafe-trait-name.rs index 2713f47ad2ff6..586c5acf21611 100644 --- a/tests/ui/derives/derive-error-identifies-unsafe-trait-name.rs +++ b/tests/ui/derives/derive-error-identifies-unsafe-trait-name.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/33571 #[derive(Clone, Sync, //~ ERROR cannot find derive macro `Sync` in this scope //~| ERROR cannot find derive macro `Sync` in this scope diff --git a/tests/ui/derives/derive-error-identifies-unsafe-trait-name.stderr b/tests/ui/derives/derive-error-identifies-unsafe-trait-name.stderr index 819a533ddbe2f..862571cb2aecd 100644 --- a/tests/ui/derives/derive-error-identifies-unsafe-trait-name.stderr +++ b/tests/ui/derives/derive-error-identifies-unsafe-trait-name.stderr @@ -1,23 +1,23 @@ error: cannot find derive macro `Sync` in this scope - --> $DIR/issue-33571.rs:2:10 + --> $DIR/derive-error-identifies-unsafe-trait-name.rs:3:10 | LL | Sync, | ^^^^ | note: unsafe traits like `Sync` should be implemented explicitly - --> $DIR/issue-33571.rs:2:10 + --> $DIR/derive-error-identifies-unsafe-trait-name.rs:3:10 | LL | Sync, | ^^^^ error: cannot find derive macro `Sync` in this scope - --> $DIR/issue-33571.rs:2:10 + --> $DIR/derive-error-identifies-unsafe-trait-name.rs:3:10 | LL | Sync, | ^^^^ | note: unsafe traits like `Sync` should be implemented explicitly - --> $DIR/issue-33571.rs:2:10 + --> $DIR/derive-error-identifies-unsafe-trait-name.rs:3:10 | LL | Sync, | ^^^^ diff --git a/tests/ui/derives/derived-trait-requires-field-impl.rs b/tests/ui/derives/derived-trait-requires-field-impl.rs index 9966c24a7441e..fb1a98c10d843 100644 --- a/tests/ui/derives/derived-trait-requires-field-impl.rs +++ b/tests/ui/derives/derived-trait-requires-field-impl.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/27340 struct Foo; #[derive(Copy, Clone)] struct Bar(Foo); diff --git a/tests/ui/derives/derived-trait-requires-field-impl.stderr b/tests/ui/derives/derived-trait-requires-field-impl.stderr index 3b4ad58b1f080..6ca75fac56937 100644 --- a/tests/ui/derives/derived-trait-requires-field-impl.stderr +++ b/tests/ui/derives/derived-trait-requires-field-impl.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/issue-27340.rs:3:8 + --> $DIR/derived-trait-requires-field-impl.rs:4:8 | LL | #[derive(Copy, Clone)] | ---- in this derive macro expansion @@ -7,7 +7,7 @@ LL | struct Bar(Foo); | ^^^ --- this field does not implement `Copy` error[E0277]: the trait bound `Foo: Clone` is not satisfied - --> $DIR/issue-27340.rs:3:12 + --> $DIR/derived-trait-requires-field-impl.rs:4:12 | LL | #[derive(Copy, Clone)] | ----- in this derive macro expansion diff --git a/tests/ui/derives/hash-on-compound-types.rs b/tests/ui/derives/hash-on-compound-types.rs index 6d950df99d65c..be7094bccc4c3 100644 --- a/tests/ui/derives/hash-on-compound-types.rs +++ b/tests/ui/derives/hash-on-compound-types.rs @@ -1,5 +1,4 @@ -//! Regression test for . - +//! Regression test for https://github.com/rust-lang/rust/issues/21402 //@ check-pass #![allow(dead_code)] diff --git a/tests/ui/derives/no-ice-on-derived-copy-with-associated-type-field.rs b/tests/ui/derives/no-ice-on-derived-copy-with-associated-type-field.rs index 50ecfe993d438..755ec1f9d5229 100644 --- a/tests/ui/derives/no-ice-on-derived-copy-with-associated-type-field.rs +++ b/tests/ui/derives/no-ice-on-derived-copy-with-associated-type-field.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/32324 //@ check-pass #![allow(dead_code)] diff --git a/tests/ui/derives/no-ice-on-path-style-derive-macro.rs b/tests/ui/derives/no-ice-on-path-style-derive-macro.rs index 86b06f7c61d0a..664fe3f241115 100644 --- a/tests/ui/derives/no-ice-on-path-style-derive-macro.rs +++ b/tests/ui/derives/no-ice-on-path-style-derive-macro.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/46101 trait Foo {} #[derive(Foo::Anything)] //~ ERROR cannot find //~| ERROR cannot find diff --git a/tests/ui/derives/no-ice-on-path-style-derive-macro.stderr b/tests/ui/derives/no-ice-on-path-style-derive-macro.stderr index 1dada87d72d64..3e05d7b384704 100644 --- a/tests/ui/derives/no-ice-on-path-style-derive-macro.stderr +++ b/tests/ui/derives/no-ice-on-path-style-derive-macro.stderr @@ -1,11 +1,11 @@ error[E0433]: cannot find derive macro `Anything` in trait `Foo` - --> $DIR/issue-46101.rs:2:10 + --> $DIR/no-ice-on-path-style-derive-macro.rs:3:10 | LL | #[derive(Foo::Anything)] | ^^^^^^^^^^^^^ a derive macro can't exist within a trait error[E0433]: cannot find derive macro `Anything` in trait `Foo` - --> $DIR/issue-46101.rs:2:10 + --> $DIR/no-ice-on-path-style-derive-macro.rs:3:10 | LL | #[derive(Foo::Anything)] | ^^^^^^^^^^^^^ a derive macro can't exist within a trait diff --git a/tests/ui/derives/no-spurious-unused-variable-warning-on-derive-hash.rs b/tests/ui/derives/no-spurious-unused-variable-warning-on-derive-hash.rs index 2181dff505ace..4609730dff385 100644 --- a/tests/ui/derives/no-spurious-unused-variable-warning-on-derive-hash.rs +++ b/tests/ui/derives/no-spurious-unused-variable-warning-on-derive-hash.rs @@ -1,3 +1,4 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/32292 //@ run-pass #![deny(warnings)] From 26ea5fe825127457ee2f0a516dca58a3e7731803 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 19 Jun 2026 08:32:09 +0200 Subject: [PATCH 064/116] internal: Do not load unnecessary path dependency files into VFS --- .../crates/project-model/src/workspace.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 675533645d0db..c9bf803da347b 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -811,6 +811,7 @@ impl ProjectWorkspace { .packages() .map(|pkg| { let is_local = cargo[pkg].is_local; + let is_member = cargo[pkg].is_member; let pkg_root = cargo[pkg].manifest.parent().to_path_buf(); let mut include = vec![pkg_root.clone()]; @@ -844,9 +845,11 @@ impl ProjectWorkspace { let mut exclude = vec![pkg_root.join(".git")]; if is_local { include.extend(self.extra_includes.iter().cloned()); - exclude.push(pkg_root.join("target")); - } else { + } + if !is_member { + // For non-workspace-members, we only resolve library targets, + // so none of these need to be loaded into the VFS. exclude.push(pkg_root.join("tests")); exclude.push(pkg_root.join("examples")); exclude.push(pkg_root.join("benches")); @@ -874,6 +877,7 @@ impl ProjectWorkspace { .chain(cargo_script.iter().flat_map(|(cargo, build_scripts, _)| { cargo.packages().map(|pkg| { let is_local = cargo[pkg].is_local; + let is_member = cargo[pkg].is_member; let pkg_root = cargo[pkg].manifest.parent().to_path_buf(); let mut include = vec![pkg_root.clone()]; @@ -909,7 +913,10 @@ impl ProjectWorkspace { include.extend(self.extra_includes.iter().cloned()); exclude.push(pkg_root.join("target")); - } else { + } + if !is_member { + // For non-workspace-members, we only resolve library targets, + // so none of these need to be loaded into the VFS. exclude.push(pkg_root.join("tests")); exclude.push(pkg_root.join("examples")); exclude.push(pkg_root.join("benches")); From ae7ee13b657518204d7c3455f6197c0abe7c46f7 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 12 Jun 2026 22:22:48 +0200 Subject: [PATCH 065/116] internal: remove unused structs --- .../rust-analyzer/crates/hir-expand/src/db.rs | 5 ----- src/tools/rust-analyzer/crates/hir-ty/src/db.rs | 17 ++--------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 513115684f872..33672d10fa6d5 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -141,11 +141,6 @@ pub trait ExpandDatabase: SourceDatabase { fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContext; } -#[salsa_macros::interned(no_lifetime, id = span::SyntaxContext, revisions = usize::MAX)] -pub struct SyntaxContextWrapper { - pub data: SyntaxContext, -} - fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> SyntaxContext { match file { HirFileId::FileId(_) => SyntaxContext::root(edition), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index baf8bbd56fb1e..93ae26abce88b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -6,8 +6,8 @@ use base_db::{Crate, target::TargetLoadError}; use either::Either; use hir_def::{ AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, EnumVariantId, - ExpressionStoreOwnerId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, - LocalFieldId, ModuleId, StaticId, TraitId, TypeAliasId, VariantId, + ExpressionStoreOwnerId, FunctionId, GenericDefId, HasModule, ImplId, LocalFieldId, ModuleId, + StaticId, TraitId, TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, expr_store::ExpressionStore, @@ -294,19 +294,6 @@ fn hir_database_is_dyn_compatible() { fn _assert_dyn_compatible(_: &dyn HirDatabase) {} } -#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] -#[derive(PartialOrd, Ord)] -pub struct InternedLifetimeParamId { - /// This stores the param and its index. - pub loc: (LifetimeParamId, u32), -} - -#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] -#[derive(PartialOrd, Ord)] -pub struct InternedConstParamId { - pub loc: ConstParamId, -} - #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedOpaqueTyId { From 8ae83150ee7a10528b7880612799ede4c3097ebe Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 19 Jun 2026 11:09:30 +0200 Subject: [PATCH 066/116] fix(implements_trait_unique_with_infcx): only forbid the self type from being an error type --- src/tools/rust-analyzer/crates/hir-ty/src/traits.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 3b5890e5e4fe1..2ca9ebe070bc9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -20,7 +20,7 @@ use hir_expand::name::Name; use intern::sym; use rustc_type_ir::{ TypeVisitableExt, TypingMode, - inherent::{BoundExistentialPredicates, GenericArg as _, IntoKind, Ty as _}, + inherent::{BoundExistentialPredicates, IntoKind, Ty as _}, }; use crate::{ @@ -153,10 +153,10 @@ pub fn implements_trait_unique_with_infcx<'db>( let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let args = create_args(&infcx); - if args.iter().filter_map(|it| it.as_type()).any(|ty| ty.is_ty_error()) { + let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args); + if trait_ref.self_ty().is_ty_error() { return false; } - let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args); let obligation = Obligation::new(interner, ObligationCause::dummy(), env.param_env, trait_ref); infcx.predicate_must_hold_modulo_regions(&obligation) From a09fc01c54cb4ba2e085612f8553fb43484964c0 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Fri, 19 Jun 2026 14:57:58 -0300 Subject: [PATCH 067/116] Avoid forcing index operand inference Adjust ambiguous index diagnostics without adding new index operand resolution points. Keep invalid operator and mismatched operand diagnostics on the operator while still pointing valid ambiguous index cases at the index operand. --- compiler/rustc_hir_typeck/src/cast.rs | 33 +++-- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 122 +++++++++++++++++- compiler/rustc_hir_typeck/src/op.rs | 9 -- .../index-expr-ambiguous-type.rs | 24 ++++ .../index-expr-ambiguous-type.stderr | 60 ++++++--- 5 files changed, 208 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 97ff7765896a8..8140788a7d988 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -725,23 +725,21 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); } - #[instrument(skip(fcx), level = "debug")] - pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { + fn expr_span_for_type_resolution(&self, fcx: &FnCtxt<'a, 'tcx>) -> Span { if let hir::ExprKind::Index(_, idx, _) = self.expr.kind - && self.expr_ty.has_infer() + && fcx.resolve_vars_if_possible(self.expr_ty).is_ty_var() + && fcx.resolve_vars_if_possible(fcx.node_ty(idx.hir_id)).is_ty_var() { - let idx_ty = fcx.resolve_vars_if_possible(fcx.node_ty(idx.hir_id)); - if idx_ty.is_ty_var() { - let resolved = fcx.structurally_resolve_type(idx.span, idx_ty); - if resolved.references_error() { - self.expr_ty = resolved; - } - } - } - // Skip if idx resolution above already emitted a diagnostic and set expr_ty to error. - if !self.expr_ty.references_error() { - self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty); + index_operand_ambiguity_span(idx) + } else { + self.expr_span } + } + + #[instrument(skip(fcx), level = "debug")] + pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { + let expr_span = self.expr_span_for_type_resolution(fcx); + self.expr_ty = fcx.structurally_resolve_type(expr_span, self.expr_ty); self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); @@ -1222,3 +1220,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } } + +fn index_operand_ambiguity_span(expr: &hir::Expr<'_>) -> Span { + match expr.kind { + hir::ExprKind::MethodCall(segment, ..) => segment.ident.span, + _ => expr.span, + } +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 825aa37065e15..2d436ec82b20e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -4,8 +4,11 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_infer::traits::ObligationCauseCode; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; use rustc_span::{Span, kw}; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; use crate::FnCtxt; @@ -37,6 +40,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, error: &mut traits::FulfillmentError<'tcx>, ) -> bool { + if self.adjust_binop_index_operand(error) { + return true; + } + let (def_id, hir_id, idx, flavor) = match *error.obligation.cause.code().peel_derives() { ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) => { (def_id, hir_id, idx, ClauseFlavor::Where) @@ -165,6 +172,119 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn adjust_binop_index_operand(&self, error: &mut traits::FulfillmentError<'tcx>) -> bool { + let ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } = + *error.obligation.cause.code().peel_derives() + else { + return false; + }; + if !matches!(error.code, traits::FulfillmentErrorCode::Ambiguity { .. }) + || !error.obligation.predicate.has_infer() + { + return false; + } + + let hir::Node::Expr(lhs_expr) = self.tcx.hir_node(lhs_hir_id) else { + return false; + }; + let hir::Node::Expr(rhs_expr) = self.tcx.hir_node(rhs_hir_id) else { + return false; + }; + let Some(binop) = self.binop_for_operands(lhs_hir_id, rhs_hir_id) else { + return false; + }; + let hir::ExprKind::Index(indexed_expr, idx, _) = rhs_expr.kind else { + return false; + }; + if !self.resolve_vars_if_possible(self.node_ty(idx.hir_id)).is_ty_var() { + return false; + } + let lhs_ty = self.resolve_vars_if_possible(self.node_ty(lhs_expr.hir_id)); + let indexed_ty = self.resolve_vars_if_possible(self.node_ty(indexed_expr.hir_id)); + let rhs_ty = match *indexed_ty.kind() { + ty::Array(element_ty, _) | ty::Slice(element_ty) => element_ty, + ty::Ref(_, pointee_ty, _) => match *pointee_ty.kind() { + ty::Array(element_ty, _) | ty::Slice(element_ty) => element_ty, + _ => self.resolve_vars_if_possible(self.node_ty(rhs_expr.hir_id)), + }, + _ => self.resolve_vars_if_possible(self.node_ty(rhs_expr.hir_id)), + }; + if !self.binop_accepts_types(binop.node, lhs_ty, rhs_ty) { + return false; + } + + error.obligation.cause.span = match idx.kind { + hir::ExprKind::MethodCall(segment, ..) => segment.ident.span, + _ => idx.span, + }; + true + } + + fn binop_for_operands( + &self, + lhs_hir_id: hir::HirId, + rhs_hir_id: hir::HirId, + ) -> Option { + let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(rhs_hir_id) else { + return None; + }; + let hir::ExprKind::Binary(binop, lhs_expr, rhs_expr) = parent_expr.kind else { + return None; + }; + (lhs_expr.hir_id == lhs_hir_id && rhs_expr.hir_id == rhs_hir_id).then_some(binop) + } + + fn binop_accepts_types( + &self, + binop: hir::BinOpKind, + lhs_ty: Ty<'tcx>, + rhs_ty: Ty<'tcx>, + ) -> bool { + let lhs_ty = self.deref_ty_if_possible(lhs_ty); + let rhs_ty = self.deref_ty_if_possible(rhs_ty); + if lhs_ty.references_error() || rhs_ty.references_error() { + return true; + } + + match binop { + hir::BinOpKind::Shl | hir::BinOpKind::Shr => { + lhs_ty.is_integral() && rhs_ty.is_integral() + } + hir::BinOpKind::Add + | hir::BinOpKind::Sub + | hir::BinOpKind::Mul + | hir::BinOpKind::Div + | hir::BinOpKind::Rem => { + self.can_eq(self.param_env, lhs_ty, rhs_ty) + && (lhs_ty.is_integral() || lhs_ty.is_floating_point()) + && (rhs_ty.is_integral() || rhs_ty.is_floating_point()) + } + hir::BinOpKind::BitXor | hir::BinOpKind::BitAnd | hir::BinOpKind::BitOr => { + self.can_eq(self.param_env, lhs_ty, rhs_ty) + && ((lhs_ty.is_integral() && rhs_ty.is_integral()) + || (lhs_ty.is_bool() && rhs_ty.is_bool())) + } + hir::BinOpKind::Eq + | hir::BinOpKind::Ne + | hir::BinOpKind::Lt + | hir::BinOpKind::Le + | hir::BinOpKind::Ge + | hir::BinOpKind::Gt => { + self.can_eq(self.param_env, lhs_ty, rhs_ty) + && lhs_ty.is_scalar() + && rhs_ty.is_scalar() + } + hir::BinOpKind::And | hir::BinOpKind::Or => lhs_ty.is_bool() && rhs_ty.is_bool(), + } + } + + fn deref_ty_if_possible(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.kind() { + ty::Ref(_, ty, hir::Mutability::Not) => *ty, + _ => ty, + } + } + fn point_at_expr_if_possible( &self, error: &mut traits::FulfillmentError<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 0a67b384ae8de..88a4241398ed8 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -314,15 +314,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); - if method.sig.output().has_infer() - && let hir::ExprKind::Index(_, idx, _) = rhs_expr.kind - { - let idx_ty = self.resolve_vars_if_possible(self.node_ty(idx.hir_id)); - if idx_ty.is_ty_var() { - self.structurally_resolve_type(idx.span, idx_ty); - } - } - method.sig.output() } // error types are considered "builtin" diff --git a/tests/ui/type-inference/index-expr-ambiguous-type.rs b/tests/ui/type-inference/index-expr-ambiguous-type.rs index 32b45703e2003..061699c8a013f 100644 --- a/tests/ui/type-inference/index-expr-ambiguous-type.rs +++ b/tests/ui/type-inference/index-expr-ambiguous-type.rs @@ -27,4 +27,28 @@ fn with_known_index_type() { let _foo = [1, 2, 3][Into::::into(bad_idx)] as i32; } +fn invalid_operator_with_ambiguous_index() { + let bad_idx = 0u8; + let _foo = true + [1, 2, 3][bad_idx.into()]; + //~^ ERROR cannot add +} + +fn mismatched_numeric_binop_with_ambiguous_index() { + let bad_idx = 0u8; + let _foo = 0u64 + [1i32, 2, 3][bad_idx.into()]; + //~^ ERROR type annotations needed +} + +fn shift_with_ambiguous_index() { + let bad_idx = 0u8; + let _foo = 1u32 << [0u8][bad_idx.into()]; + //~^ ERROR type annotations needed +} + +fn string_add_with_ambiguous_index() { + let bad_idx = 0u8; + let _foo = String::new() + [""][bad_idx.into()]; + //~^ ERROR type annotations needed +} + fn main() {} diff --git a/tests/ui/type-inference/index-expr-ambiguous-type.stderr b/tests/ui/type-inference/index-expr-ambiguous-type.stderr index 80c0aa6c4a952..83de98d80cae6 100644 --- a/tests/ui/type-inference/index-expr-ambiguous-type.stderr +++ b/tests/ui/type-inference/index-expr-ambiguous-type.stderr @@ -2,25 +2,15 @@ error[E0282]: type annotations needed --> $DIR/index-expr-ambiguous-type.rs:9:34 | LL | let _foo = [1, 2, 3][bad_idx.into()] as i32; - | ^^^^ - | -help: try using a fully qualified path to specify the expected types - | -LL - let _foo = [1, 2, 3][bad_idx.into()] as i32; -LL + let _foo = [1, 2, 3][>::into(bad_idx)] as i32; - | + | ^^^^ cannot infer type -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/index-expr-ambiguous-type.rs:15:38 | LL | let _foo = 0 + [1, 2, 3][bad_idx.into()]; - | ^^^^ - | -help: try using a fully qualified path to specify the expected types - | -LL - let _foo = 0 + [1, 2, 3][bad_idx.into()]; -LL + let _foo = 0 + [1, 2, 3][>::into(bad_idx)]; + | ^^^^ cannot infer type | + = note: cannot satisfy `>::Output == _` error[E0283]: type annotations needed --> $DIR/index-expr-ambiguous-type.rs:21:34 @@ -36,7 +26,45 @@ LL - let _foo = [1, 2, 3][bad_idx.into()]; LL + let _foo = [1, 2, 3][>::into(bad_idx)]; | -error: aborting due to 3 previous errors +error[E0369]: cannot add `_` to `bool` + --> $DIR/index-expr-ambiguous-type.rs:32:21 + | +LL | let _foo = true + [1, 2, 3][bad_idx.into()]; + | ---- ^ ------------------------- _ + | | + | bool + +error[E0284]: type annotations needed + --> $DIR/index-expr-ambiguous-type.rs:38:21 + | +LL | let _foo = 0u64 + [1i32, 2, 3][bad_idx.into()]; + | ^ cannot infer type + | + = note: cannot satisfy `>::Output == _` + +error[E0284]: type annotations needed + --> $DIR/index-expr-ambiguous-type.rs:44:38 + | +LL | let _foo = 1u32 << [0u8][bad_idx.into()]; + | ^^^^ cannot infer type + | + = note: cannot satisfy `>::Output == _` + +error[E0283]: type annotations needed + --> $DIR/index-expr-ambiguous-type.rs:50:45 + | +LL | let _foo = String::new() + [""][bad_idx.into()]; + | ^^^^ + | + = note: the type must implement `From` + = note: required for `u8` to implement `Into<_>` +help: try using a fully qualified path to specify the expected types + | +LL - let _foo = String::new() + [""][bad_idx.into()]; +LL + let _foo = String::new() + [""][>::into(bad_idx)]; + | + +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0282, E0283. +Some errors have detailed explanations: E0282, E0283, E0284, E0369. For more information about an error, try `rustc --explain E0282`. From a2f80c97243067708527f1d4f5d2bb5db75e4dff Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Fri, 19 Jun 2026 17:22:18 -0300 Subject: [PATCH 068/116] Handle alias outlives ambiguity during rewrite --- .../rustc_type_ir/src/region_constraint.rs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index b896d7a398178..ddace4b941a43 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -654,18 +654,8 @@ fn pull_region_outlives_constraints_out_of_universe< use RegionConstraint::*; match constraint { Ambiguity | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => { - // With only lifetime binders the rewrite step lowers these constraints out of `u` - // (or destructures them), so we expect `max_universe < u` here. A non-lifetime - // binder (`for`) instead introduces a placeholder type in `u`, which - // `PlaceholderReplacer` (region-only, see its `fold_region`) cannot pull out, - // leaving e.g. `::Assoc: 'r` stranded in `u`. The assumptions-on-binders - // machinery is region-outlives-only and can't decide such a constraint, so report - // ambiguity rather than ICE. - if max_universe(infcx, constraint.clone()) < u { - constraint - } else { - RegionConstraint::Ambiguity - } + assert!(max_universe(infcx, constraint.clone()) < u); + constraint } RegionOutlives(region_1, region_2) => { let region_1_u = max_universe(infcx, region_1); @@ -850,7 +840,15 @@ fn rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling< escaping_outlives, I::BoundVarKinds::from_vars(infcx.cx(), bound_vars), ); - candidates.push(RegionConstraint::AliasTyOutlivesViaEnv(bound_outlives)); + let candidate = RegionConstraint::AliasTyOutlivesViaEnv(bound_outlives); + if max_universe(infcx, candidate.clone()) < u { + candidates.push(candidate); + } else { + // `PlaceholderReplacer` only folds regions. A non-lifetime binder can leave + // a placeholder type in `u`, so this type-outlives constraint cannot be + // handled by the region-outlives-only eager placeholder machinery. + candidates.push(Ambiguity); + } } let assumptions = match assumptions { @@ -895,12 +893,17 @@ fn rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling< // while we did skip the binder, bound vars aren't in any universe so // this can't be an escaping bound var - candidates.extend( - regions_outliving(escaping_r, assumptions, infcx.cx()) - .filter(|r2| max_universe(infcx, *r2) < u) - .map(|r2| AliasTyOutlivesViaEnv(bound_alias.map_bound(|alias| (alias, r2)))) - .collect::>(), - ); + for r2 in regions_outliving(escaping_r, assumptions, infcx.cx()) + .filter(|r2| max_universe(infcx, *r2) < u) + { + let candidate = + AliasTyOutlivesViaEnv(bound_alias.map_bound(|alias| (alias, r2))); + if max_universe(infcx, candidate.clone()) < u { + candidates.push(candidate); + } else { + candidates.push(Ambiguity); + } + } } // I'm not convinced our handling here is *complete* so for now From 542e70fa844da86dfbc33f0481d7e82983026d3f Mon Sep 17 00:00:00 2001 From: shulaoda <165626830+shulaoda@users.noreply.github.com> Date: Sat, 20 Jun 2026 08:10:14 +0800 Subject: [PATCH 069/116] fix: Don't panic on out-of-range integer literals in const positions --- .../rust-analyzer/crates/hir-ty/src/consteval.rs | 16 ++++++++++++---- .../hir-ty/src/tests/regression/new_solver.rs | 10 ++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index d6580d3752f6b..a880ae5353b66 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -87,18 +87,24 @@ fn intern_const_ref<'db>( let valtree = match (ty.kind(), value) { (TyKind::Uint(uint), Literal::Uint(value, _)) => { let size = uint.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size()); - let scalar = ScalarInt::try_from_uint(*value, size).unwrap(); + let Some(scalar) = ScalarInt::try_from_uint(*value, size) else { + return Ok(Const::error(interner)); + }; ValTreeKind::Leaf(scalar) } (TyKind::Uint(uint), Literal::Int(value, _)) => { // `Literal::Int` is the default, so we also need to account for the type being uint. let size = uint.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size()); - let scalar = ScalarInt::try_from_uint(*value as u128, size).unwrap(); + let Some(scalar) = ScalarInt::try_from_uint(*value as u128, size) else { + return Ok(Const::error(interner)); + }; ValTreeKind::Leaf(scalar) } (TyKind::Int(int), Literal::Int(value, _)) => { let size = int.bit_width().map(Size::from_bits).unwrap_or(data_layout.pointer_size()); - let scalar = ScalarInt::try_from_int(*value, size).unwrap(); + let Some(scalar) = ScalarInt::try_from_int(*value, size) else { + return Ok(Const::error(interner)); + }; ValTreeKind::Leaf(scalar) } (TyKind::Bool, Literal::Bool(value)) => ValTreeKind::Leaf(ScalarInt::from(*value)), @@ -219,7 +225,9 @@ pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option, krate: Cr return Const::error(interner); }; let usize_ty = interner.default_types().types.usize; - let scalar = ScalarInt::try_from_uint(value, data_layout.pointer_size()).unwrap(); + let Some(scalar) = ScalarInt::try_from_uint(value, data_layout.pointer_size()) else { + return Const::error(interner); + }; Const::new_valtree(interner, usize_ty, ValTreeKind::Leaf(scalar)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 17127b2771d2e..fb00a755fa055 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -404,6 +404,16 @@ const A: [u8; S] = [0; 8]; ); } +#[test] +fn oversized_array_len_does_not_panic() { + // The array length literal does not fit in `usize`; interning it must not panic. + check_no_mismatches( + r#" +fn f(_: [u8; 18446744073709551616]) {} + "#, + ); +} + #[test] fn another_20654_case() { check_no_mismatches( From af7cb85aa9677c57e224d6c25bc562f0fa604f59 Mon Sep 17 00:00:00 2001 From: Raushan kumar Date: Sat, 20 Jun 2026 04:52:21 +0000 Subject: [PATCH 070/116] fix(toolchain): use std::env::home_dir instead of home crate --- src/tools/rust-analyzer/Cargo.lock | 10 ---------- src/tools/rust-analyzer/crates/toolchain/Cargo.toml | 1 - src/tools/rust-analyzer/crates/toolchain/src/lib.rs | 2 +- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 5e39dfe87004b..38aa3050f4f82 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1002,15 +1002,6 @@ dependencies = [ "typed-arena", ] -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "icu_collections" version = "2.2.0" @@ -3148,7 +3139,6 @@ name = "toolchain" version = "0.0.0" dependencies = [ "camino", - "home", ] [[package]] diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml index f561c1c0e2b0e..d0d5840e785a0 100644 --- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml +++ b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml @@ -13,7 +13,6 @@ rust-version.workspace = true doctest = false [dependencies] -home = "0.5.11" camino.workspace = true [lints] diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs index 39319886cfe4a..ea08f7aacac4e 100644 --- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs +++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs @@ -119,7 +119,7 @@ fn get_cargo_home() -> Option { return Utf8PathBuf::try_from(PathBuf::from(path)).ok(); } - if let Some(mut path) = home::home_dir() { + if let Some(mut path) = env::home_dir() { path.push(".cargo"); return Utf8PathBuf::try_from(path).ok(); } From b860d7b6c2bd99fe9ddb275fea93232f4ee9ed0f Mon Sep 17 00:00:00 2001 From: Benjamin Brienen Date: Sat, 20 Jun 2026 07:15:51 +0200 Subject: [PATCH 071/116] Fix release pipeline by pinning node docker image. See nodejs/node#63989 --- .../rust-analyzer/.github/actions/github-release/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile b/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile index 5849eac7d246a..ad296ce74152f 100644 --- a/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile +++ b/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile @@ -1,4 +1,4 @@ -FROM node:slim +FROM node:24.16-slim@sha256:ca520832af80fa37a57c14077ed0fcdd83b5aefccc356059fdc3a9a05b78ae1f COPY . /action WORKDIR /action From 837f5bf3eceb8daeefd953625f3514d812a55b8a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 20 Jun 2026 13:43:48 +0200 Subject: [PATCH 072/116] Track salsa cancellation time in loop turn warning --- .../crates/ide-db/src/apply_change.rs | 7 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 5 +- .../crates/rust-analyzer/src/global_state.rs | 8 +- .../crates/rust-analyzer/src/main_loop.rs | 85 ++++++++++++------- .../crates/rust-analyzer/src/reload.rs | 44 +++++----- .../crates/rust-analyzer/src/task_pool.rs | 4 - 6 files changed, 91 insertions(+), 62 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index b77a18f56ea21..7a3c466daa50c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -1,16 +1,21 @@ //! Applies changes to the IDE state transactionally. +use std::time::{Duration, Instant}; + use profile::Bytes; use salsa::Database as _; use crate::{ChangeWithProcMacros, RootDatabase}; impl RootDatabase { - pub fn apply_change(&mut self, change: ChangeWithProcMacros) { + pub fn apply_change(&mut self, change: ChangeWithProcMacros) -> Duration { let _p = tracing::info_span!("RootDatabase::apply_change").entered(); + let now = Instant::now(); self.trigger_cancellation(); + let elapsed = now.elapsed(); tracing::trace!("apply_change {:?}", change); change.apply(self); + elapsed } // Feature: Memory Usage diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 88cb570c6b0f3..dded01520ffbc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -60,6 +60,7 @@ mod view_mir; mod view_syntax_tree; use std::panic::{AssertUnwindSafe, UnwindSafe}; +use std::time::Duration; use cfg::CfgOptions; use fetch_crates::CrateInfo; @@ -197,8 +198,8 @@ impl AnalysisHost { /// Applies changes to the current state of the world. If there are /// outstanding snapshots, they will be canceled. - pub fn apply_change(&mut self, change: ChangeWithProcMacros) { - self.db.apply_change(change); + pub fn apply_change(&mut self, change: ChangeWithProcMacros) -> Duration { + self.db.apply_change(change) } /// NB: this clears the database diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index afd4162de6227..f91e9532aaf02 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -330,7 +330,7 @@ impl GlobalState { this } - pub(crate) fn process_changes(&mut self) -> bool { + pub(crate) fn process_changes(&mut self) -> (bool, Option) { let _p = span!(Level::INFO, "GlobalState::process_changes").entered(); // We cannot directly resolve a change in a ratoml file to a format // that can be used by the config module because config talks @@ -343,7 +343,7 @@ impl GlobalState { let mut guard = self.vfs.write(); let changed_files = guard.0.take_changes(); if changed_files.is_empty() { - return false; + return (false, None); } let (change, modified_rust_files, workspace_structure_change) = @@ -439,7 +439,7 @@ impl GlobalState { (change, modified_rust_files, workspace_structure_change) }); - self.analysis_host.apply_change(change); + let cancellation_time = self.analysis_host.apply_change(change); if !modified_ratoml_files.is_empty() || !self.config.same_source_root_parent_map(&self.local_roots_parent_map) @@ -561,7 +561,7 @@ impl GlobalState { } } - true + (true, Some(cancellation_time)) } pub(crate) fn snapshot(&self) -> GlobalStateSnapshot { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 628e708c6a83d..d966e29ede0c4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -307,15 +307,11 @@ impl GlobalState { let _p = tracing::info_span!("GlobalState::handle_event", event = %event).entered(); let event_dbg_msg = format!("{event:?}"); - tracing::debug!(?loop_start, ?event, "handle_event"); - if tracing::enabled!(tracing::Level::TRACE) { - let task_queue_len = self.task_pool.handle.len(); - if task_queue_len > 0 { - tracing::trace!("task queue len: {}", task_queue_len); - } - } + tracing::debug!(?event, "handle_event"); let was_quiescent = self.is_quiescent(); + + let mut cancellation_time = None; match event { Event::Lsp(msg) => match msg { lsp_server::Message::Request(req) => self.on_new_request(loop_start, req), @@ -326,7 +322,9 @@ impl GlobalState { let _p = tracing::info_span!("GlobalState::handle_event/queued_task").entered(); self.handle_deferred_task(task); // Coalesce multiple deferred task events into one loop turn - while let Ok(task) = self.deferred_task_queue.receiver.try_recv() { + while loop_start.elapsed() < Duration::from_millis(50) + && let Ok(task) = self.deferred_task_queue.receiver.try_recv() + { self.handle_deferred_task(task); } } @@ -334,14 +332,16 @@ impl GlobalState { let _p = tracing::info_span!("GlobalState::handle_event/task").entered(); let mut prime_caches_progress = Vec::new(); - self.handle_task(&mut prime_caches_progress, task); + cancellation_time = self.handle_task(&mut prime_caches_progress, task); // Coalesce multiple task events into one loop turn - while let Ok(task) = self.task_pool.receiver.try_recv() { + while loop_start.elapsed() < Duration::from_millis(50) + && let Ok(task) = self.task_pool.receiver.try_recv() + { self.handle_task(&mut prime_caches_progress, task); } let title = "Indexing"; - let cancel_token = Some("rustAnalyzer/cachePriming".to_owned()); + let cancel_token = || Some("rustAnalyzer/cachePriming".to_owned()); let mut last_report = None; for progress in prime_caches_progress { @@ -352,7 +352,7 @@ impl GlobalState { Progress::Begin, None, Some(0.0), - cancel_token.clone(), + cancel_token(), ); } PrimeCachesProgress::Report(report) => { @@ -404,7 +404,7 @@ impl GlobalState { Progress::Report, message, Some(fraction), - cancel_token.clone(), + cancel_token(), ); } self.report_progress( @@ -412,7 +412,7 @@ impl GlobalState { Progress::End, None, Some(1.0), - cancel_token.clone(), + cancel_token(), ); } }; @@ -423,7 +423,7 @@ impl GlobalState { Progress::Report, message, Some(fraction), - cancel_token.clone(), + cancel_token(), ); } } @@ -432,7 +432,9 @@ impl GlobalState { let mut last_progress_report = None; self.handle_vfs_msg(message, &mut last_progress_report); // Coalesce many VFS event into a single loop turn - while let Ok(message) = self.loader.receiver.try_recv() { + while loop_start.elapsed() < Duration::from_millis(50) + && let Ok(message) = self.loader.receiver.try_recv() + { self.handle_vfs_msg(message, &mut last_progress_report); } if let Some((message, fraction)) = last_progress_report { @@ -449,7 +451,9 @@ impl GlobalState { let mut cargo_finished = false; self.handle_flycheck_msg(message, &mut cargo_finished); // Coalesce many flycheck updates into a single loop turn - while let Ok(message) = self.flycheck_receiver.try_recv() { + while loop_start.elapsed() < Duration::from_millis(50) + && let Ok(message) = self.flycheck_receiver.try_recv() + { self.handle_flycheck_msg(message, &mut cargo_finished); } if cargo_finished { @@ -463,14 +467,18 @@ impl GlobalState { let _p = tracing::info_span!("GlobalState::handle_event/test_result").entered(); self.handle_cargo_test_msg(message); // Coalesce many test result event into a single loop turn - while let Ok(message) = self.test_run_receiver.try_recv() { + while loop_start.elapsed() < Duration::from_millis(50) + && let Ok(message) = self.test_run_receiver.try_recv() + { self.handle_cargo_test_msg(message); } } Event::DiscoverProject(message) => { self.handle_discover_msg(message); // Coalesce many project discovery events into a single loop turn. - while let Ok(message) = self.discover_receiver.try_recv() { + while loop_start.elapsed() < Duration::from_millis(50) + && let Ok(message) = self.discover_receiver.try_recv() + { self.handle_discover_msg(message); } } @@ -479,13 +487,23 @@ impl GlobalState { } } let event_handling_duration = loop_start.elapsed(); - let (state_changed, memdocs_added_or_removed) = if self.vfs_done { - if let Some(cause) = self.wants_to_switch.take() { - self.switch_workspaces(cause); - } - (self.process_changes(), self.mem_docs.take_changes()) - } else { - (false, false) + let ((state_changed, changes_cancellation_time), memdocs_added_or_removed) = + if self.vfs_done { + if let Some(cause) = self.wants_to_switch.take() { + cancellation_time = match (cancellation_time, self.switch_workspaces(cause)) { + (Some(a), Some(b)) => Some(a + b), + (Some(d), None) | (None, Some(d)) => Some(d), + (None, None) => None, + }; + } + (self.process_changes(), self.mem_docs.take_changes()) + } else { + ((false, None), false) + }; + cancellation_time = match (cancellation_time, changes_cancellation_time) { + (Some(a), Some(b)) => Some(a + b), + (Some(d), None) | (None, Some(d)) => Some(d), + (None, None) => None, }; let mut gc_elapsed = None; @@ -609,11 +627,13 @@ impl GlobalState { tracing::warn!( "overly long loop turn took {loop_duration:?}:\n\ (event handling took {event_handling_duration:?}): {event_dbg_msg}\n\ + (cancellation took {cancellation_time:?}) (garbage collection took {gc_elapsed:?})" ); self.poke_rust_analyzer_developer(format!( "overly long loop turn took {loop_duration:?}:\n\ (event handling took {event_handling_duration:?}): {event_dbg_msg}\n\ + (cancellation took {cancellation_time:?}) (garbage collection took {gc_elapsed:?})" )); } @@ -819,7 +839,12 @@ impl GlobalState { } } - fn handle_task(&mut self, prime_caches_progress: &mut Vec, task: Task) { + fn handle_task( + &mut self, + prime_caches_progress: &mut Vec, + task: Task, + ) -> Option { + let mut cancellation_time = None; match task { Task::Response(response) => self.respond(response), // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work. @@ -922,8 +947,9 @@ impl GlobalState { ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)), ProcMacroProgress::End(change) => { self.fetch_proc_macros_queue.op_completed(true); - self.analysis_host.apply_change(change); - self.finish_loading_crate_graph(); + cancellation_time = Some(self.analysis_host.apply_change(change)); + // FIXME This feels a bit off, this should go through similar machinery as build scripts? + _ = self.finish_loading_crate_graph(); (Some(Progress::End), None) } }; @@ -937,6 +963,7 @@ impl GlobalState { self.send_notification::(tests); } } + cancellation_time } fn handle_vfs_msg( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 74fd0e653398b..4940defed2ac2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -13,7 +13,7 @@ //! project is currently loading and we don't have a full project model, we //! still want to respond to various requests. // FIXME: This is a mess that needs some untangling work -use std::{iter, mem, sync::atomic::AtomicUsize}; +use std::{iter, mem, sync::atomic::AtomicUsize, time::Duration}; use hir::{ChangeWithProcMacros, ProcMacrosBuilder, db::DefDatabase}; use ide_db::{ @@ -468,25 +468,22 @@ impl GlobalState { }); } - pub(crate) fn switch_workspaces(&mut self, cause: Cause) { + pub(crate) fn switch_workspaces(&mut self, cause: Cause) -> Option { let _p = tracing::info_span!("GlobalState::switch_workspaces").entered(); tracing::info!(%cause, "will switch workspaces"); - let Some(FetchWorkspaceResponse { workspaces, force_crate_graph_reload }) = - self.fetch_workspaces_queue.last_op_result() - else { - return; - }; + let FetchWorkspaceResponse { workspaces, force_crate_graph_reload } = + self.fetch_workspaces_queue.last_op_result()?; let switching_from_empty_workspace = self.workspaces.is_empty(); info!(%cause, ?force_crate_graph_reload, %switching_from_empty_workspace); if self.fetch_workspace_error().is_err() && !switching_from_empty_workspace { if *force_crate_graph_reload { - self.recreate_crate_graph(cause, false); + return self.recreate_crate_graph(cause, false); } // It only makes sense to switch to a partially broken workspace // if we don't have any workspace at all yet. - return; + return None; } let workspaces = @@ -501,7 +498,7 @@ impl GlobalState { if same_workspaces { if switching_from_empty_workspace { // Switching from empty to empty is a no-op - return; + return None; } if let Some(FetchBuildDataResponse { workspaces, build_scripts }) = self.fetch_build_data_queue.last_op_result() @@ -524,20 +521,20 @@ impl GlobalState { } else { info!("build scripts do not match the version of the active workspace"); if *force_crate_graph_reload { - self.recreate_crate_graph(cause, switching_from_empty_workspace); + return self.recreate_crate_graph(cause, switching_from_empty_workspace); } // Current build scripts do not match the version of the active // workspace, so there's nothing for us to update. - return; + return None; } } else { if *force_crate_graph_reload { - self.recreate_crate_graph(cause, switching_from_empty_workspace); + return self.recreate_crate_graph(cause, switching_from_empty_workspace); } // No build scripts but unchanged workspaces, nothing to do here - return; + return None; } } else { info!("abandon build scripts for workspaces"); @@ -560,7 +557,7 @@ impl GlobalState { // `switch_workspaces()` will be called again when build scripts already run, which should // take a short time. If we update the workspace now we will invalidate proc macros and cfgs, // and then when build scripts complete we will invalidate them again. - return; + return None; } } } @@ -733,13 +730,15 @@ impl GlobalState { self.local_roots_parent_map = Arc::new(self.source_root_config.source_root_parent_map()); info!(?cause, "recreating the crate graph"); - self.recreate_crate_graph(cause, switching_from_empty_workspace); + let cancellation_time = self.recreate_crate_graph(cause, switching_from_empty_workspace); info!("did switch workspaces"); + cancellation_time } - fn recreate_crate_graph(&mut self, cause: String, initial_build: bool) { + fn recreate_crate_graph(&mut self, cause: String, initial_build: bool) -> Option { info!(?cause, "Building Crate Graph"); + let mut cancellation_time = None; self.report_progress( "Building CrateGraph", crate::lsp::utils::Progress::Begin, @@ -795,9 +794,8 @@ impl GlobalState { } change.set_crate_graph(crate_graph); - self.analysis_host.apply_change(change); - - self.finish_loading_crate_graph(); + cancellation_time = Some(self.analysis_host.apply_change(change)); + _ = self.finish_loading_crate_graph(); } else { change.set_crate_graph(crate_graph); self.fetch_proc_macros_queue.request_op(cause, (change, proc_macro_paths)); @@ -810,11 +808,13 @@ impl GlobalState { None, None, ); + cancellation_time } - pub(crate) fn finish_loading_crate_graph(&mut self) { - self.process_changes(); + pub(crate) fn finish_loading_crate_graph(&mut self) -> Option { + let (_, cancellation_time) = self.process_changes(); self.reload_flycheck(); + cancellation_time } pub(super) fn fetch_workspace_error(&self) -> Result<(), String> { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs index 104cd3d2eae9e..2da52f7480d8a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs @@ -40,10 +40,6 @@ impl TaskPool { }) } - pub(crate) fn len(&self) -> usize { - self.pool.len() - } - pub(crate) fn is_empty(&self) -> bool { self.pool.is_empty() } From 303b159ae7f7acf4998ee7871da01c27376aa2e6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 20 Jun 2026 17:33:14 +0200 Subject: [PATCH 073/116] Take &SyntaxFactory instead of &SyntaxEditor in merge/normalize import APIs try_merge_imports, try_merge_trees, and try_normalize_import only ever used the editor to obtain its SyntaxFactory; they never edited through it. --- .../ide-assists/src/handlers/merge_imports.rs | 4 ++-- .../src/handlers/normalize_import.rs | 2 +- .../crates/ide-db/src/imports/insert_use.rs | 4 +++- .../ide-db/src/imports/insert_use/tests.rs | 13 ++++++----- .../ide-db/src/imports/merge_imports.rs | 23 +++++++------------ .../rust-analyzer/crates/parser/src/output.rs | 2 +- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index e942be33d94c5..5d81f49b18507 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -98,7 +98,7 @@ fn merge_uses( }; let mut merged = first.clone(); for item in &rest { - merged = try_merge_imports(editor, &merged, item, mb)?; + merged = try_merge_imports(editor.make(), &merged, item, mb)?; } for item in rest { item.remove(editor); @@ -118,7 +118,7 @@ fn merge_use_trees( let mut merged = first.clone(); for item in &rest { - merged = try_merge_trees(editor, &merged, item, MergeBehavior::Crate)?; + merged = try_merge_trees(editor.make(), &merged, item, MergeBehavior::Crate)?; } for item in rest { item.remove(editor); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs index 07571d74d8b8d..906f38cba407f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs @@ -27,7 +27,7 @@ pub(crate) fn normalize_import(acc: &mut Assists, ctx: &AssistContext<'_, '_>) - let target = use_item.syntax().text_range(); let (editor, _) = SyntaxEditor::new(use_item.syntax().ancestors().last().unwrap()); let normalized_use_item = - try_normalize_import(&editor, &use_item, ctx.config.insert_use.granularity.into())?; + try_normalize_import(editor.make(), &use_item, ctx.config.insert_use.granularity.into())?; editor.replace(use_item.syntax(), normalized_use_item.syntax()); acc.add(AssistId::refactor_rewrite("normalize_import"), "Normalize import", target, |builder| { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index 1fd493fd2a730..27e3ed6bdb52e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -263,7 +263,9 @@ fn insert_use_with_alias_option_with_editor( for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter) { - if let Some(merged) = try_merge_imports(syntax_editor, &existing_use, &use_item, mb) { + if let Some(merged) = + try_merge_imports(syntax_editor.make(), &existing_use, &use_item, mb) + { syntax_editor.replace(existing_use.syntax(), merged.syntax()); return; } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index a30d290490210..34ff7c8d5b426 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -1,4 +1,5 @@ use stdx::trim_indent; +use syntax::ast::syntax_factory::SyntaxFactory; use test_fixture::WithFixture; use test_utils::{CURSOR_MARKER, assert_eq_text}; @@ -1430,8 +1431,8 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior .find_map(ast::Use::cast) .unwrap(); - let (editor, _) = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()); - let result = try_merge_imports(&editor, &use0, &use1, mb); + let make = SyntaxFactory::without_mappings(); + let result = try_merge_imports(&make, &use0, &use1, mb); assert_eq!(result.map(|u| u.to_string()), None); } @@ -1496,8 +1497,8 @@ fn check_merge(ra_fixture0: &str, ra_fixture1: &str, last: &str, mb: MergeBehavi .find_map(ast::Use::cast) .unwrap(); - let (editor, _) = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()); - let result = try_merge_imports(&editor, &use0, &use1, mb); + let make = SyntaxFactory::without_mappings(); + let result = try_merge_imports(&make, &use0, &use1, mb); assert_eq!(result.map(|u| u.to_string().trim().to_owned()), Some(last.trim().to_owned())); } @@ -1527,8 +1528,8 @@ fn merge_gated_imports_with_different_values() { .find_map(ast::Use::cast) .unwrap(); - let (editor, _) = SyntaxEditor::new(use0.syntax().ancestors().last().unwrap()); - let result = try_merge_imports(&editor, &use0, &use1, MergeBehavior::Crate); + let make = SyntaxFactory::without_mappings(); + let result = try_merge_imports(&make, &use0, &use1, MergeBehavior::Crate); assert_eq!(result, None); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index 95e654df174f5..9b68c27ae3443 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -40,7 +40,7 @@ impl MergeBehavior { /// Merge `rhs` into `lhs` keeping both intact. pub fn try_merge_imports( - editor: &SyntaxEditor, + make: &SyntaxFactory, lhs: &ast::Use, rhs: &ast::Use, merge_behavior: MergeBehavior, @@ -53,7 +53,6 @@ pub fn try_merge_imports( return None; } - let make = editor.make(); let lhs_tree = lhs.use_tree()?; let rhs_tree = rhs.use_tree()?; let merged_tree = try_merge_trees_with_factory(lhs_tree, rhs_tree, merge_behavior, make)?; @@ -67,12 +66,11 @@ pub fn try_merge_imports( /// Merge `rhs` into `lhs` keeping both intact. pub fn try_merge_trees( - editor: &SyntaxEditor, + make: &SyntaxFactory, lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior, ) -> Option { - let make = editor.make(); let merged = try_merge_trees_with_factory(lhs.clone(), rhs.clone(), merge, make)?; // Ignore `None` result because normalization should not affect the merge result. @@ -100,15 +98,11 @@ fn try_merge_trees_with_factory( { // we can't merge if the renames are different (`A as a` and `A as b`), // and we can safely return here - let lhs_name = lhs - .rename() - .and_then(|lhs_name| lhs_name.name()) - .map(|name| name.text().to_string()); - let rhs_name = rhs - .rename() - .and_then(|rhs_name| rhs_name.name()) - .map(|name| name.text().to_string()); - if lhs_name != rhs_name { + let lhs_name = lhs.rename().and_then(|lhs_name| lhs_name.name()); + let rhs_name = rhs.rename().and_then(|rhs_name| rhs_name.name()); + if lhs_name.as_ref().map(|name| name.text()) + != rhs_name.as_ref().map(|name| name.text()) + { return None; } @@ -263,11 +257,10 @@ impl From for NormalizationStyle { /// - `foo::bar::{self}` -> `{foo::bar}` /// - `foo::bar` -> `{foo::bar}` pub fn try_normalize_import( - editor: &SyntaxEditor, + make: &SyntaxFactory, use_item: &ast::Use, style: NormalizationStyle, ) -> Option { - let make = editor.make(); let use_tree = try_normalize_use_tree(use_item.use_tree()?, style, make)?; make_use_with_tree(use_item, use_tree) diff --git a/src/tools/rust-analyzer/crates/parser/src/output.rs b/src/tools/rust-analyzer/crates/parser/src/output.rs index 2f09b1121891b..ce64db8adae90 100644 --- a/src/tools/rust-analyzer/crates/parser/src/output.rs +++ b/src/tools/rust-analyzer/crates/parser/src/output.rs @@ -18,7 +18,7 @@ pub struct Output { /// /// ```text /// |16 bit kind|8 bit n_input_tokens|4 bit tag|4 bit leftover| - /// `````` + /// ``` event: Vec, error: Vec, } From a408c10cc061ccbf5de24177c447d205b878f73e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 20 Jun 2026 17:36:56 +0200 Subject: [PATCH 074/116] Consolidate Use/UseTree editor removal into the Removable trait ast::edit had private inherent ast::Use::remove and ast::UseTree::remove_with_editor methods that duplicated the --- .../crates/syntax/src/ast/edit.rs | 69 +------------------ .../crates/syntax/src/syntax_editor/edits.rs | 24 ++++++- 2 files changed, 25 insertions(+), 68 deletions(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index 0155df8aa0b86..2448809a840b8 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -2,7 +2,6 @@ //! immutable, all function here return a fresh copy of the tree, instead of //! doing an in-place modification. use parser::T; -use rowan::Direction; use std::{ fmt, iter::{self, once}, @@ -13,9 +12,8 @@ use crate::{ AstToken, NodeOrToken, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, SyntaxNode, SyntaxToken, - algo::neighbor, ast::{self, AstNode, HasName, make}, - syntax_editor::{Position, SyntaxEditor, SyntaxMappingBuilder}, + syntax_editor::{Position, Removable, SyntaxEditor, SyntaxMappingBuilder}, }; use super::syntax_factory::SyntaxFactory; @@ -286,24 +284,6 @@ impl ast::GenericParamList { } impl ast::UseTree { - /// Editor variant of UseTree remove - fn remove_with_editor(&self, editor: &SyntaxEditor) { - for dir in [Direction::Next, Direction::Prev] { - if let Some(next_use_tree) = neighbor(self, dir) { - let separators = self - .syntax() - .siblings_with_tokens(dir) - .skip(1) - .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); - for separator in separators { - editor.delete(separator); - } - break; - } - } - editor.delete(self.syntax()); - } - /// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty. pub fn remove_recursive(self, editor: &SyntaxEditor) { let parent = self.syntax().parent(); @@ -319,7 +299,7 @@ impl ast::UseTree { u.parent_use_tree().remove_recursive(editor); return; } - self.remove_with_editor(editor); + self.remove(editor); u.remove_unnecessary_braces(editor); } } @@ -365,51 +345,6 @@ impl ast::UseTree { } } -impl ast::Use { - fn remove(&self, editor: &SyntaxEditor) { - let make = editor.make(); - let next_ws = self - .syntax() - .next_sibling_or_token() - .and_then(|it| it.into_token()) - .and_then(ast::Whitespace::cast); - if let Some(next_ws) = next_ws { - let ws_text = next_ws.syntax().text(); - if let Some(rest) = ws_text.strip_prefix('\n') { - let next_use_removed = next_ws - .syntax() - .next_sibling_or_token() - .and_then(|it| it.into_node()) - .and_then(ast::Use::cast) - .and_then(|use_| use_.use_tree()) - .is_some_and(|use_tree| editor.deleted(use_tree.syntax())); - if rest.is_empty() || next_use_removed { - editor.delete(next_ws.syntax()); - } else { - editor.replace(next_ws.syntax(), make.whitespace(rest)); - } - } - } - let prev_ws = self - .syntax() - .prev_sibling_or_token() - .and_then(|it| it.into_token()) - .and_then(ast::Whitespace::cast); - if let Some(prev_ws) = prev_ws { - let ws_text = prev_ws.syntax().text(); - let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0); - let rest = &ws_text[0..prev_newline]; - if rest.is_empty() { - editor.delete(prev_ws.syntax()); - } else { - editor.replace(prev_ws.syntax(), make.whitespace(rest)); - } - } - - editor.delete(self.syntax()); - } -} - impl ast::RecordExprField { /// This will either replace the initializer, or in the case that this is a shorthand convert /// the initializer into the name ref and insert the expr as the new initializer. diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index f2b979eb9d1ae..9fab8716b412f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -459,13 +459,35 @@ impl Removable for ast::Use { if let Some(next_ws) = next_ws { let ws_text = next_ws.syntax().text(); if let Some(rest) = ws_text.strip_prefix('\n') { - if rest.is_empty() { + let next_use_removed = next_ws + .syntax() + .next_sibling_or_token() + .and_then(|it| it.into_node()) + .and_then(ast::Use::cast) + .and_then(|use_| use_.use_tree()) + .is_some_and(|use_tree| editor.deleted(use_tree.syntax())); + if rest.is_empty() || next_use_removed { editor.delete(next_ws.syntax()); } else { editor.replace(next_ws.syntax(), make.whitespace(rest)); } } } + let prev_ws = self + .syntax() + .prev_sibling_or_token() + .and_then(|it| it.into_token()) + .and_then(ast::Whitespace::cast); + if let Some(prev_ws) = prev_ws { + let ws_text = prev_ws.syntax().text(); + let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0); + let rest = &ws_text[0..prev_newline]; + if rest.is_empty() { + editor.delete(prev_ws.syntax()); + } else { + editor.replace(prev_ws.syntax(), make.whitespace(rest)); + } + } editor.delete(self.syntax()); } From 9e66c39de321917a9d19f68a64e6fd1155679b48 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 20 Jun 2026 17:45:04 +0200 Subject: [PATCH 075/116] Add regression tests for UseTree::split_prefix_with_editor --- .../crates/syntax/src/ast/edit.rs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index 2448809a840b8..eaa36903bf26f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -313,7 +313,7 @@ impl ast::UseTree { /// /// `prefix$0` -> `prefix::{self}` /// - /// `prefix$0::*` -> `prefix::{*}```` + /// `prefix$0::*` -> `prefix::{*}` pub fn split_prefix_with_editor(&self, editor: &SyntaxEditor, prefix: &ast::Path) { debug_assert_eq!(self.path(), Some(prefix.top_path())); @@ -388,3 +388,29 @@ fn test_increase_indent() { }" ); } + +#[test] +fn split_prefix_inserts_self() { + check_split_prefix("use foo;", "foo::{self}"); +} + +#[test] +fn split_prefix_preserves_rename() { + check_split_prefix("use foo as bar;", "foo::{self as bar}"); +} + +#[test] +fn split_prefix_wraps_glob() { + check_split_prefix("use foo::*;", "foo::{*}"); +} + +#[cfg(test)] +fn check_split_prefix(before: &str, expected: &str) { + let source = crate::SourceFile::parse(before, parser::Edition::CURRENT).tree(); + let use_tree = source.syntax().descendants().find_map(ast::UseTree::cast).unwrap(); + let (editor, use_tree) = SyntaxEditor::with_ast_node(&use_tree); + let prefix = use_tree.path().unwrap(); + use_tree.split_prefix_with_editor(&editor, &prefix); + let edit = editor.finish(); + assert_eq!(edit.new_root().to_string(), expected); +} From d873a79b8a310cb6c18f3a96edcfd050a5ed0e81 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 3 Jun 2026 08:53:16 +0530 Subject: [PATCH 076/116] bye bye ted --- .../rust-analyzer/crates/syntax/src/lib.rs | 1 - .../rust-analyzer/crates/syntax/src/ted.rs | 227 ------------------ 2 files changed, 228 deletions(-) delete mode 100644 src/tools/rust-analyzer/crates/syntax/src/ted.rs diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index cda3e69b7c625..924e72ee40397 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -39,7 +39,6 @@ pub mod ast; pub mod fuzz; pub mod hacks; pub mod syntax_editor; -pub mod ted; pub mod utils; use std::{marker::PhantomData, ops::Range}; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ted.rs b/src/tools/rust-analyzer/crates/syntax/src/ted.rs deleted file mode 100644 index 5c286479c4e3d..0000000000000 --- a/src/tools/rust-analyzer/crates/syntax/src/ted.rs +++ /dev/null @@ -1,227 +0,0 @@ -//! Primitive tree editor, ed for trees. -//! -//! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix -//! up elements around the edges. -use std::{mem, ops::RangeInclusive}; - -use parser::T; -use rowan::TextSize; - -use crate::{ - SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, - ast::{self, AstNode, edit::IndentLevel, make}, -}; - -/// Utility trait to allow calling `ted` functions with references or owned -/// nodes. Do not use outside of this module. -pub trait Element { - fn syntax_element(self) -> SyntaxElement; -} - -impl Element for &'_ E { - fn syntax_element(self) -> SyntaxElement { - self.clone().syntax_element() - } -} -impl Element for SyntaxElement { - fn syntax_element(self) -> SyntaxElement { - self - } -} -impl Element for SyntaxNode { - fn syntax_element(self) -> SyntaxElement { - self.into() - } -} -impl Element for SyntaxToken { - fn syntax_element(self) -> SyntaxElement { - self.into() - } -} - -#[derive(Debug)] -pub struct Position { - repr: PositionRepr, -} - -#[derive(Debug)] -enum PositionRepr { - FirstChild(SyntaxNode), - After(SyntaxElement), -} - -impl Position { - pub fn after(elem: impl Element) -> Position { - let repr = PositionRepr::After(elem.syntax_element()); - Position { repr } - } - pub fn before(elem: impl Element) -> Position { - let elem = elem.syntax_element(); - let repr = match elem.prev_sibling_or_token() { - Some(it) => PositionRepr::After(it), - None => PositionRepr::FirstChild(elem.parent().unwrap()), - }; - Position { repr } - } - pub fn first_child_of(node: &(impl Into + Clone)) -> Position { - let repr = PositionRepr::FirstChild(node.clone().into()); - Position { repr } - } - pub fn last_child_of(node: &(impl Into + Clone)) -> Position { - let node = node.clone().into(); - let repr = match node.last_child_or_token() { - Some(it) => PositionRepr::After(it), - None => PositionRepr::FirstChild(node), - }; - Position { repr } - } - pub fn offset(&self) -> TextSize { - match &self.repr { - PositionRepr::FirstChild(node) => node.text_range().start(), - PositionRepr::After(elem) => elem.text_range().end(), - } - } -} - -pub fn insert(position: Position, elem: impl Element) { - insert_all(position, vec![elem.syntax_element()]); -} -pub fn insert_raw(position: Position, elem: impl Element) { - insert_all_raw(position, vec![elem.syntax_element()]); -} -pub fn insert_all(position: Position, mut elements: Vec) { - if let Some(first) = elements.first() - && let Some(ws) = ws_before(&position, first) - { - elements.insert(0, ws.into()); - } - if let Some(last) = elements.last() - && let Some(ws) = ws_after(&position, last) - { - elements.push(ws.into()); - } - insert_all_raw(position, elements); -} -pub fn insert_all_raw(position: Position, elements: Vec) { - let (parent, index) = match position.repr { - PositionRepr::FirstChild(parent) => (parent, 0), - PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1), - }; - parent.splice_children(index..index, elements); -} - -pub fn remove(elem: impl Element) { - elem.syntax_element().detach(); -} -pub fn remove_all(range: RangeInclusive) { - replace_all(range, Vec::new()); -} -pub fn remove_all_iter(range: impl IntoIterator) { - let mut it = range.into_iter(); - if let Some(mut first) = it.next() { - match it.last() { - Some(mut last) => { - if first.index() > last.index() { - mem::swap(&mut first, &mut last); - } - remove_all(first..=last); - } - None => remove(first), - } - } -} - -pub fn replace(old: impl Element, new: impl Element) { - replace_with_many(old, vec![new.syntax_element()]); -} -pub fn replace_with_many(old: impl Element, new: Vec) { - let old = old.syntax_element(); - replace_all(old.clone()..=old, new); -} -pub fn replace_all(range: RangeInclusive, new: Vec) { - let start = range.start().index(); - let end = range.end().index(); - let parent = range.start().parent().unwrap(); - parent.splice_children(start..end + 1, new); -} - -pub fn append_child(node: &(impl Into + Clone), child: impl Element) { - let position = Position::last_child_of(node); - insert(position, child); -} -pub fn append_child_raw(node: &(impl Into + Clone), child: impl Element) { - let position = Position::last_child_of(node); - insert_raw(position, child); -} - -pub fn prepend_child(node: &(impl Into + Clone), child: impl Element) { - let position = Position::first_child_of(node); - insert(position, child); -} - -fn ws_before(position: &Position, new: &SyntaxElement) -> Option { - let prev = match &position.repr { - PositionRepr::FirstChild(_) => return None, - PositionRepr::After(it) => it, - }; - - if prev.kind() == T!['{'] - && new.kind() == SyntaxKind::USE - && let Some(item_list) = prev.parent().and_then(ast::ItemList::cast) - { - let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into()); - indent.0 += 1; - return Some(make::tokens::whitespace(&format!("\n{indent}"))); - } - - if prev.kind() == T!['{'] - && ast::Stmt::can_cast(new.kind()) - && let Some(stmt_list) = prev.parent().and_then(ast::StmtList::cast) - { - let mut indent = IndentLevel::from_element(&stmt_list.syntax().clone().into()); - indent.0 += 1; - return Some(make::tokens::whitespace(&format!("\n{indent}"))); - } - - ws_between(prev, new) -} -fn ws_after(position: &Position, new: &SyntaxElement) -> Option { - let next = match &position.repr { - PositionRepr::FirstChild(parent) => parent.first_child_or_token()?, - PositionRepr::After(sibling) => sibling.next_sibling_or_token()?, - }; - ws_between(new, &next) -} -fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option { - if left.kind() == SyntaxKind::WHITESPACE || right.kind() == SyntaxKind::WHITESPACE { - return None; - } - if right.kind() == T![;] || right.kind() == T![,] { - return None; - } - if left.kind() == T![<] || right.kind() == T![>] { - return None; - } - if left.kind() == T![&] && right.kind() == SyntaxKind::LIFETIME { - return None; - } - if right.kind() == SyntaxKind::GENERIC_ARG_LIST { - return None; - } - - if right.kind() == SyntaxKind::USE { - let mut indent = IndentLevel::from_element(left); - if left.kind() == SyntaxKind::USE { - indent.0 = IndentLevel::from_element(right).0.max(indent.0); - } - return Some(make::tokens::whitespace(&format!("\n{indent}"))); - } - if left.kind() == SyntaxKind::ATTR { - let mut indent = IndentLevel::from_element(right); - if right.kind() == SyntaxKind::ATTR { - indent.0 = IndentLevel::from_element(left).0.max(indent.0); - } - return Some(make::tokens::whitespace(&format!("\n{indent}"))); - } - Some(make::tokens::single_space()) -} From 8dae4577de433e1dbe30c77bb81023784ee9d43d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 21 Jun 2026 00:28:08 +0800 Subject: [PATCH 077/116] internal: add merge imports indent tests --- .../ide-assists/src/handlers/merge_imports.rs | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index 5d81f49b18507..4234a6090dc3f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -535,6 +535,62 @@ use foo::{bar, baz}; ); } + #[test] + fn mod_indent_whitespace() { + check_assist( + merge_imports, + r" +mod tests { + use foo$0::bar; + use foo::baz; + fn feature() {} +} +", + r" +mod tests { + use foo::{bar, baz}; + fn feature() {} +} +", + ); + check_assist( + merge_imports, + r" +mod tests { + use foo$0::bar; + use foo::baz; + + fn feature() {} +} +", + r" +mod tests { + use foo::{bar, baz}; + + fn feature() {} +} +", + ); + check_assist( + merge_imports, + r" +mod tests { + use foo::bar; + use foo$0::baz; + + fn feature() {} +} +", + r" +mod tests { + use foo::{bar, baz}; + + fn feature() {} +} +", + ); + } + #[test] fn works_with_trailing_comma() { check_assist( From 3bb0a1c892df204b9cdeca8aa394e7367680db9f Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sat, 20 Jun 2026 15:54:57 -0300 Subject: [PATCH 078/116] Resolve vars before computing max universe --- compiler/rustc_type_ir/src/region_constraint.rs | 14 ++++---------- .../resolved-region-var-max-universe.rs | 8 +++++--- .../resolved-region-var-max-universe.stderr | 4 ++-- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 6f13eedda4983..3bc0502b4f3cb 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -978,11 +978,14 @@ pub fn regions_outlived_by_placeholder( } /// The largest universe a variable or placeholder was from in `t` -pub fn max_universe, I: Interner, T: TypeVisitable>( +pub fn max_universe, I: Interner, T: TypeFoldable>( infcx: &Infcx, t: T, ) -> UniverseIndex { let mut visitor = MaxUniverse::new(infcx); + // `max_universe` is also used while rewriting constraints to lower universes, + // so do not rely on callers having already resolved non-region infer vars. + let t = infcx.resolve_vars_if_possible(t); t.visit_with(&mut visitor); visitor.max_universe() } @@ -1013,10 +1016,6 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match t.kind() { TyKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), TyKind::Infer(InferTy::TyVar(inf)) => { - // Unlike `visit_region`, we don't resolve the variable first: callers - // computing assumptions bail on any non-region inference variable - // before reaching here, so a type infer var is always unresolved and - // has a universe. let u = self.infcx.universe_of_ty(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1029,8 +1028,6 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match c.kind() { ConstKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), ConstKind::Infer(rustc_type_ir::InferConst::Var(inf)) => { - // See the comment in `visit_ty`: a const infer var is always - // unresolved here, so unlike a region it needs no resolving first. let u = self.infcx.universe_of_ct(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1043,9 +1040,6 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match r.kind() { RegionKind::RePlaceholder(p) => self.max_universe = self.max_universe.max(p.universe), RegionKind::ReVar(var) => { - // The variable may already have been unified with another region. - // `universe_of_lt` returns `None` for a resolved variable, so resolve - // it first and inspect whatever it points at. match self.infcx.opportunistic_resolve_lt_var(var).kind() { RegionKind::RePlaceholder(p) => { self.max_universe = self.max_universe.max(p.universe) diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs index f0286fb92453a..46c9aacdd93d9 100644 --- a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs @@ -3,8 +3,10 @@ // Regression test for an ICE in the `MaxUniverse` region visitor. When computing // the max universe of a region constraint, a `ReVar` term could already have been // unified with another region. `universe_of_lt` returns `None` for such a resolved -// variable, so the visitor used to `unwrap()` `None` and panic. It now resolves the -// variable before inspecting its universe. +// variable, so the visitor used to `unwrap()` `None` and panic. +// +// The missing `T` in `check` is intentional. It makes HIR ty lowering emit an +// error while still leaving behind the region constraint that used to ICE. #![feature(min_generic_const_args, inherent_associated_types, generic_const_items)] @@ -16,7 +18,7 @@ impl<'a> Parent<'a> { type const CT: usize = 0; } -fn check/**/() +fn check() where [(); Parent::CT::]:, //~^ ERROR cannot find type `T` in this scope diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr index 6fa91876dd47b..e77a0994fc2db 100644 --- a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr @@ -1,12 +1,12 @@ error[E0425]: cannot find type `T` in this scope - --> $DIR/resolved-region-var-max-universe.rs:21:23 + --> $DIR/resolved-region-var-max-universe.rs:23:23 | LL | [(); Parent::CT::]:, | ^ not found in this scope | help: you might be missing a type parameter | -LL | fn check/**/() +LL | fn check() | +++ error: aborting due to 1 previous error From a44ab8d43042ffe67ab5e288a765f181d4474dc4 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sat, 20 Jun 2026 16:05:13 -0300 Subject: [PATCH 079/116] Format max universe visitor --- .../rustc_type_ir/src/region_constraint.rs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 3bc0502b4f3cb..2ba2d40f3a540 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -1039,19 +1039,17 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor fn visit_region(&mut self, r: I::Region) { match r.kind() { RegionKind::RePlaceholder(p) => self.max_universe = self.max_universe.max(p.universe), - RegionKind::ReVar(var) => { - match self.infcx.opportunistic_resolve_lt_var(var).kind() { - RegionKind::RePlaceholder(p) => { - self.max_universe = self.max_universe.max(p.universe) - } - RegionKind::ReVar(var) => { - let u = self.infcx.universe_of_lt(var).unwrap(); - debug!("var {var:?} in universe {u:?}"); - self.max_universe = self.max_universe.max(u); - } - _ => (), + RegionKind::ReVar(var) => match self.infcx.opportunistic_resolve_lt_var(var).kind() { + RegionKind::RePlaceholder(p) => { + self.max_universe = self.max_universe.max(p.universe) } - } + RegionKind::ReVar(var) => { + let u = self.infcx.universe_of_lt(var).unwrap(); + debug!("var {var:?} in universe {u:?}"); + self.max_universe = self.max_universe.max(u); + } + _ => (), + }, _ => (), } } From b93879b81c9529155b4fa68885f0ab882f867f89 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 20 Jun 2026 18:28:13 +0200 Subject: [PATCH 080/116] Do not visit nodes in GC multiple times --- .../crates/hir-ty/src/next_solver/interner.rs | 4 +- .../rust-analyzer/crates/intern/Cargo.toml | 1 - .../rust-analyzer/crates/intern/src/gc.rs | 44 +++++++++++++------ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 9875a915dcdda..ef626fc0c8869 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -2629,8 +2629,8 @@ macro_rules! impl_gc_visit_slice { } #[inline] - fn visit_slice(header: &[::SliceType], gc: &mut ::intern::GarbageCollector) { - header.generic_visit_with(gc); + fn visit_slice(slice: &[::SliceType], gc: &mut ::intern::GarbageCollector) { + slice.generic_visit_with(gc); } } )* diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml index 2ba802f05706c..adf49ca7b6c29 100644 --- a/src/tools/rust-analyzer/crates/intern/Cargo.toml +++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml @@ -12,7 +12,6 @@ rust-version.workspace = true [lib] doctest = false - [dependencies] dashmap.workspace = true # We need to freeze the version of the crate, as it needs to match with dashmap diff --git a/src/tools/rust-analyzer/crates/intern/src/gc.rs b/src/tools/rust-analyzer/crates/intern/src/gc.rs index f4e8f75e7194b..596b05eb1cb13 100644 --- a/src/tools/rust-analyzer/crates/intern/src/gc.rs +++ b/src/tools/rust-analyzer/crates/intern/src/gc.rs @@ -34,9 +34,7 @@ impl Storage for InternedStorage { for item in storage { let item = item.key(); let addr = Arc::as_ptr(item).addr(); - if Arc::strong_count(item) > 1 { - // The item is referenced from the outside. - gc.alive.insert(addr); + if Arc::strong_count(item) > 1 && gc.alive.insert(addr) { item.visit_with(gc); } } @@ -60,9 +58,7 @@ impl Storage for InternedSliceStorage for item in storage { let item = item.key(); let addr = ThinArc::as_ptr(item).addr(); - if ThinArc::strong_count(item) > 1 { - // The item is referenced from the outside. - gc.alive.insert(addr); + if ThinArc::strong_count(item) > 1 && gc.alive.insert(addr) { T::visit_header(&item.header.header, gc); T::visit_slice(&item.slice, gc); } @@ -81,7 +77,7 @@ pub trait GcInternedVisit { pub trait GcInternedSliceVisit: SliceInternable { fn visit_header(header: &Self::Header, gc: &mut GarbageCollector); - fn visit_slice(header: &[Self::SliceType], gc: &mut GarbageCollector); + fn visit_slice(slice: &[Self::SliceType], gc: &mut GarbageCollector); } #[derive(Default)] @@ -103,11 +99,13 @@ impl GarbageCollector { self.storages.push(&InternedSliceStorage::(PhantomData)); } + /// Collects unreachable GC-managed interned values. + /// /// # Safety /// /// - This cannot be called if there are some not-yet-recorded type values. - /// - All relevant storages must have been added; that is, within the full graph of values, - /// the added storages must form a DAG. + /// - All storages that can contain live GC-managed values must have been added, and those + /// storages must be closed over the GC-managed values reachable from them. /// - [`GcInternedVisit`] and [`GcInternedSliceVisit`] must mark all values reachable from the node. pub unsafe fn collect(mut self) { if cfg!(feature = "prevent-gc") { @@ -136,8 +134,9 @@ impl GarbageCollector { &mut self, interned: InternedRef<'_, T>, ) -> ControlFlow<()> { + const { assert!(T::USE_GC) }; + if interned.strong_count() > 1 { - // It will be visited anyway, so short-circuit return ControlFlow::Break(()); } let addr = interned.as_raw().addr(); @@ -148,8 +147,9 @@ impl GarbageCollector { &mut self, interned: InternedSliceRef<'_, T>, ) -> ControlFlow<()> { + const { assert!(T::USE_GC) }; + if interned.strong_count() > 1 { - // It will be visited anyway, so short-circuit return ControlFlow::Break(()); } let addr = interned.as_raw().addr(); @@ -240,7 +240,7 @@ mod tests { impl GcInternedSliceVisit for StringSlice { fn visit_header(_header: &Self::Header, _gc: &mut GarbageCollector) {} - fn visit_slice(_header: &[Self::SliceType], _gc: &mut GarbageCollector) {} + fn visit_slice(_slice: &[Self::SliceType], _gc: &mut GarbageCollector) {} } let (a, d) = { @@ -276,6 +276,10 @@ mod tests { gc.add_storage::(); unsafe { gc.collect() }; + if !cfg!(feature = "prevent-gc") { + assert_eq!(::storage().get().len(), 1); + assert_eq!(::storage().get().len(), 1); + } assert_eq!(a.0, "abc"); assert_eq!(d.header.length, 2); assert_eq!(d.header.header, "abc"); @@ -288,6 +292,11 @@ mod tests { gc.add_slice_storage::(); gc.add_storage::(); unsafe { gc.collect() }; + + if !cfg!(feature = "prevent-gc") { + assert_eq!(::storage().get().len(), 0); + assert_eq!(::storage().get().len(), 0); + } } #[test] @@ -309,7 +318,7 @@ mod tests { impl GcInternedSliceVisit for StringSlice { fn visit_header(_header: &Self::Header, _gc: &mut GarbageCollector) {} - fn visit_slice(_header: &[Self::SliceType], _gc: &mut GarbageCollector) {} + fn visit_slice(_slice: &[Self::SliceType], _gc: &mut GarbageCollector) {} } let outer = { @@ -322,6 +331,10 @@ mod tests { gc.add_storage::(); unsafe { gc.collect() }; + if !cfg!(feature = "prevent-gc") { + assert_eq!(::storage().get().len(), 1); + assert_eq!(::storage().get().len(), 1); + } assert_eq!(outer.0.header.header, "abc"); assert_eq!(outer.0.slice, [123, 456, 789]); @@ -331,5 +344,10 @@ mod tests { gc.add_slice_storage::(); gc.add_storage::(); unsafe { gc.collect() }; + + if !cfg!(feature = "prevent-gc") { + assert_eq!(::storage().get().len(), 0); + assert_eq!(::storage().get().len(), 0); + } } } From 1d5426573496501457364d1d20d443d7472a234f Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 17 Jun 2026 22:49:27 +0200 Subject: [PATCH 081/116] Optimize network address parser Split `read_number()` into seperate methods for the the `max_digits` `Some(_)` and `None` cases. Hoist reading the first digit which is always required. The path for unlimited digits then no longer has to count digits at all. --- library/core/src/net/parser.rs | 97 +++++++++++++++------------------- 1 file changed, 44 insertions(+), 53 deletions(-) diff --git a/library/core/src/net/parser.rs b/library/core/src/net/parser.rs index 3aab24a90d817..a6473735dd455 100644 --- a/library/core/src/net/parser.rs +++ b/library/core/src/net/parser.rs @@ -63,11 +63,6 @@ impl<'a> Parser<'a> { if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind)) } - /// Peek the next character from the input - fn peek_char(&self) -> Option { - self.state.first().map(|&b| char::from(b)) - } - /// Reads the next character from the input fn read_char(&mut self) -> Option { self.state.split_first().map(|(&b, tail)| { @@ -100,60 +95,56 @@ impl<'a> Parser<'a> { }) } - // Read a number off the front of the input in the given radix, stopping - // at the first non-digit character or eof. Fails if the number has more - // digits than max_digits or if there is no number. - // - // INVARIANT: `max_digits` must be less than the number of digits that `u32` - // can represent. - fn read_number>( + /// Reads a number off the front of the input in the given radix, stopping at the first + /// non-digit character or eof. Fails if the number has more digits than `max_digits`, if there + /// is no number, if the number overflows `T`, or if there are leading zeros but + /// `allow_zero_prefix` is false. + /// + /// `max_digits` must be in 1..=6. + fn read_radix_max_digits>( &mut self, radix: u32, - max_digits: Option, + max_digits: u32, allow_zero_prefix: bool, ) -> Option { - self.read_atomically(move |p| { - let mut digit_count = 0; - let has_leading_zero = p.peek_char() == Some('0'); - - // If max_digits.is_some(), then we are parsing a `u8` or `u16` and - // don't need to use checked arithmetic since it fits within a `u32`. - let result = if let Some(max_digits) = max_digits { - // u32::MAX = 4_294_967_295u32, which is 10 digits long. - // `max_digits` must be less than 10 to not overflow a `u32`. - debug_assert!(max_digits < 10); - - let mut result = 0_u32; - while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { - result *= radix; - result += digit; - digit_count += 1; - - if digit_count > max_digits { - return None; - } - } - - result.try_into().ok() - } else { - let mut result = T::ZERO; + debug_assert!(1 <= max_digits); + debug_assert!(max_digits <= 6); // Works for any radix in u32 + self.read_atomically(|p| { + let first = p.read_char()?.to_digit(radix)?; + let mut result = first; + let mut digit_count = 1; - while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { - result = result.checked_mul(radix)?; - result = result.checked_add(digit)?; - digit_count += 1; + while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { + if digit_count >= max_digits { + return None; } + result *= radix; + result += digit; + digit_count += 1; + } - Some(result) - }; - - if digit_count == 0 { - None - } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 { + if !allow_zero_prefix && first == 0 && digit_count > 1 { None } else { - result + result.try_into().ok() + } + }) + } + + /// Reads a decimal number off the front of the input, stopping at the first non-digit character + /// or eof. Fails if there is no number, or if the number overflows `T`. Allows an arbitrary + /// amount of leading zeros. + fn read_decimal(&mut self) -> Option { + self.read_atomically(|p| { + let first = p.read_char()?.to_digit(10)?; + let mut result = T::ZERO.checked_add(first)?; + + while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(10)) { + result = result.checked_mul(10)?; + result = result.checked_add(digit)?; } + + Some(result) }) } @@ -166,7 +157,7 @@ impl<'a> Parser<'a> { *slot = p.read_separator('.', i, |p| { // Disallow octal number in IP string. // https://tools.ietf.org/html/rfc6943#section-3.1.1 - p.read_number(10, Some(3), false) + p.read_radix_max_digits(10, 3, false) })?; } @@ -198,7 +189,7 @@ impl<'a> Parser<'a> { } } - let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true)); + let group = p.read_separator(':', i, |p| p.read_radix_max_digits(16, 4, true)); match group { Some(g) => *slot = g, @@ -250,7 +241,7 @@ impl<'a> Parser<'a> { fn read_port(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char(':')?; - p.read_number(10, None, true) + p.read_decimal() }) } @@ -258,7 +249,7 @@ impl<'a> Parser<'a> { fn read_scope_id(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char('%')?; - p.read_number(10, None, true) + p.read_decimal() }) } From fc7e417bf6e69250a8e48024a07500ae29f1e6d0 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 18 Jun 2026 17:02:50 +0200 Subject: [PATCH 082/116] fix(assists/replace_match_with_if_let): don't parenthesize if-let guards --- .../src/handlers/replace_if_let_with_match.rs | 73 ++++++++++++++++++- .../crates/ide-assists/src/utils.rs | 20 +++++ .../crates/syntax/src/ast/prec.rs | 23 ++++++ 3 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 6959988db7f03..5225202177111 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -17,7 +17,7 @@ use crate::{ AssistContext, AssistId, Assists, utils::{ does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block, - wrap_paren, + wrap_paren_in_guard_chain, }, }; @@ -303,7 +303,7 @@ pub(crate) fn replace_match_with_if_let( _ => make.expr_let(if_let_pat, scrutinee).into(), }; let condition = if let Some(guard) = guard { - let guard = wrap_paren(guard, make, ast::prec::ExprPrecedence::LAnd); + let guard = wrap_paren_in_guard_chain(guard, make); make.expr_bin(condition, ast::BinaryOp::LogicOp(ast::LogicOp::And), guard).into() } else { condition @@ -2454,7 +2454,7 @@ fn main() { } #[test] - fn test_replace_match_with_if_let_chain() { + fn test_replace_match_with_if_let_with_simple_guard() { check_assist( replace_match_with_if_let, r#" @@ -2498,6 +2498,73 @@ fn main() { ); } + #[test] + fn test_replace_match_with_if_let_with_if_let_guard() { + check_assist( + replace_match_with_if_let, + r#" +fn main() { + match$0 Some(0) { + Some(n) if let Some(m) = n.checked_add(1) => (), + _ => code(), + } +} +"#, + r#" +fn main() { + if let Some(n) = Some(0) && let Some(m) = n.checked_add(1) { + () + } else { + code() + } +} +"#, + ); + + check_assist( + replace_match_with_if_let, + r#" +fn main() { + match$0 Some(0) { + Some(n) if let Some(m) = n.checked_add(1) && m > 5 => (), + _ => code(), + } +} + "#, + r#" +fn main() { + if let Some(n) = Some(0) && let Some(m) = n.checked_add(1) && m > 5 { + () + } else { + code() + } +} + "#, + ); + + // what if the `let` expr is not the first one in the guard? + check_assist( + replace_match_with_if_let, + r#" +fn main() { + match$0 Some(0) { + Some(n) if n > 5 && let Some(m) = n.checked_add(1) => (), + _ => code(), + } +} + "#, + r#" +fn main() { + if let Some(n) = Some(0) && n > 5 && let Some(m) = n.checked_add(1) { + () + } else { + code() + } +} + "#, + ); + } + #[test] fn test_replace_match_with_if_let_not_applicable_pat2_is_ident_pat() { check_assist_not_applicable( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 086f54ed17f69..2c4fb5f405a77 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -110,6 +110,26 @@ fn needs_parens_in_call(make: &SyntaxFactory, param: &ast::Expr) -> bool { param.needs_parens_in_place_of(call.syntax(), callable.syntax()) } +pub(crate) fn wrap_paren_in_guard_chain(guard: ast::Expr, make: &SyntaxFactory) -> ast::Expr { + if needs_parens_in_guard_chain(make, &guard) { make.expr_paren(guard).into() } else { guard } +} + +fn needs_parens_in_guard_chain(make: &SyntaxFactory, guard: &ast::Expr) -> bool { + let ast::Expr::BinExpr(if_let_and_guard) = make.expr_bin_op( + make.expr_unit(), + ast::BinaryOp::LogicOp(ast::LogicOp::And), + make.expr_unit(), + ) else { + stdx::never!("`SyntaxFactory::expr_bin_op` returns a `BinExpr`"); + return false; + }; + let Some(fake_guard) = if_let_and_guard.rhs() else { + stdx::never!("invalid make call"); + return false; + }; + guard.needs_parens_in_place_of(if_let_and_guard.syntax(), fake_guard.syntax()) +} + /// This is a method with a heuristics to support test methods annotated with custom test annotations, such as /// `#[test_case(...)]`, `#[tokio::test]` and similar. /// Also a regular `#[test]` annotation is supported. diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs index 8411275350542..2a50d233c3bfb 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs @@ -264,6 +264,14 @@ impl Expr { return false; } + // Special-case `cond && ` + if let ast::Expr::BinExpr(parent) = parent + && parent.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) + && self.contains_let_expr() + { + return false; + } + let (left, right, inv) = match self.is_ordered_before_parent_in_place_of(parent, place_of) { true => (self, parent, false), false => (parent, self, true), @@ -551,4 +559,19 @@ impl Expr { ForExpr(_) | IfExpr(_) | MatchExpr(_) | WhileExpr(_) | IncludeBytesExpr(_) => true, } } + + fn contains_let_expr(&self) -> bool { + use Expr::*; + + match self { + LetExpr(_) => true, + BinExpr(e) => { + // if we find something other than a `&&`, then this can't be a let chain + e.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) + && (e.lhs().is_none_or(|it| it.contains_let_expr()) + || e.rhs().is_none_or(|it| it.contains_let_expr())) + } + _ => false, + } + } } From e7b8d13714f087dbc0bdeb30db2c3b17ea71b99e Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sun, 21 Jun 2026 14:55:15 -0300 Subject: [PATCH 083/116] Ignore println newline in foreign format hints --- compiler/rustc_builtin_macros/src/format.rs | 4 +++- .../format-foreign-dollar-without-spec.stderr | 14 ++++++-------- tests/ui/macros/issue-92267.stderr | 14 ++++++-------- .../trailing-percent-format-hint-issue-158216.rs | 7 +++++++ ...railing-percent-format-hint-issue-158216.stderr | 14 ++++++++++++++ 5 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 tests/ui/macros/trailing-percent-format-hint-issue-158216.rs create mode 100644 tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 007251ff3df05..89ea581d34d60 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -607,6 +607,8 @@ fn make_format_args( // If there's a lot of unused arguments, // let's check if this format arguments looks like another syntax (printf / shell). let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2; + let foreign_fmt_str = + if append_newline { fmt_str.strip_suffix('\n').unwrap_or(fmt_str) } else { fmt_str }; report_missing_placeholders( ecx, unused, @@ -616,7 +618,7 @@ fn make_format_args( &invalid_refs, detect_foreign_fmt, str_style, - fmt_str, + foreign_fmt_str, uncooked_fmt_str.1.as_str(), fmt_span, ); diff --git a/tests/ui/macros/format-foreign-dollar-without-spec.stderr b/tests/ui/macros/format-foreign-dollar-without-spec.stderr index d5a07c50f00d0..87d86061188af 100644 --- a/tests/ui/macros/format-foreign-dollar-without-spec.stderr +++ b/tests/ui/macros/format-foreign-dollar-without-spec.stderr @@ -2,15 +2,13 @@ error: argument never used --> $DIR/format-foreign-dollar-without-spec.rs:3:25 | LL | println!("%65536$", 1); - | ^ argument never used + | --------- ^ argument never used + | | + | formatting specifier missing | -note: format specifiers use curly braces, and the conversion specifier ` - ` is unknown or unsupported - --> $DIR/format-foreign-dollar-without-spec.rs:3:15 +help: format specifiers use curly braces, consider adding a format specifier | -LL | println!("%65536$", 1); - | ^^^^^^^^ - = note: printf formatting is not supported; see the documentation for `std::fmt` +LL | println!("%65536${}", 1); + | ++ error: aborting due to 1 previous error - diff --git a/tests/ui/macros/issue-92267.stderr b/tests/ui/macros/issue-92267.stderr index 4259815328b30..8f8d345f51b5f 100644 --- a/tests/ui/macros/issue-92267.stderr +++ b/tests/ui/macros/issue-92267.stderr @@ -2,15 +2,13 @@ error: argument never used --> $DIR/issue-92267.rs:3:34 | LL | pub fn main() { println!("🦀%%%", 0) } - | ^ argument never used + | ------- ^ argument never used + | | + | formatting specifier missing | -note: format specifiers use curly braces, and the conversion specifier ` - ` is unknown or unsupported - --> $DIR/issue-92267.rs:3:30 +help: format specifiers use curly braces, consider adding a format specifier | -LL | pub fn main() { println!("🦀%%%", 0) } - | ^^ - = note: printf formatting is not supported; see the documentation for `std::fmt` +LL | pub fn main() { println!("🦀%%%{}", 0) } + | ++ error: aborting due to 1 previous error - diff --git a/tests/ui/macros/trailing-percent-format-hint-issue-158216.rs b/tests/ui/macros/trailing-percent-format-hint-issue-158216.rs new file mode 100644 index 0000000000000..bebea2dfe48c6 --- /dev/null +++ b/tests/ui/macros/trailing-percent-format-hint-issue-158216.rs @@ -0,0 +1,7 @@ +//@ check-fail +//@ compile-flags: --crate-type=lib + +pub fn f(x: f64) { + println!("{x:>8.2}%", "foo"); + //~^ ERROR argument never used +} diff --git a/tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr b/tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr new file mode 100644 index 0000000000000..2b18d0193441d --- /dev/null +++ b/tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr @@ -0,0 +1,14 @@ +error: argument never used + --> $DIR/trailing-percent-format-hint-issue-158216.rs:5:27 + | +LL | println!("{x:>8.2}%", "foo"); + | ----------- ^^^^^ argument never used + | | + | formatting specifier missing + | +help: format specifiers use curly braces, consider adding a format specifier + | +LL | println!("{x:>8.2}%{}", "foo"); + | ++ + +error: aborting due to 1 previous error From 56dfba726240149fc2e67d4ac37f2d72ebbf0e1c Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sun, 21 Jun 2026 16:50:20 -0300 Subject: [PATCH 084/116] Update foreign format UI baselines --- tests/ui/macros/format-foreign-dollar-without-spec.stderr | 1 + tests/ui/macros/issue-92267.stderr | 5 +++-- .../macros/trailing-percent-format-hint-issue-158216.stderr | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/ui/macros/format-foreign-dollar-without-spec.stderr b/tests/ui/macros/format-foreign-dollar-without-spec.stderr index 87d86061188af..c4c241048abb0 100644 --- a/tests/ui/macros/format-foreign-dollar-without-spec.stderr +++ b/tests/ui/macros/format-foreign-dollar-without-spec.stderr @@ -12,3 +12,4 @@ LL | println!("%65536${}", 1); | ++ error: aborting due to 1 previous error + diff --git a/tests/ui/macros/issue-92267.stderr b/tests/ui/macros/issue-92267.stderr index 8f8d345f51b5f..7bbbb28cdacad 100644 --- a/tests/ui/macros/issue-92267.stderr +++ b/tests/ui/macros/issue-92267.stderr @@ -1,14 +1,15 @@ error: argument never used --> $DIR/issue-92267.rs:3:34 | -LL | pub fn main() { println!("🦀%%%", 0) } +LL | pub fn main() { println!("🦀%%%", 0) } //~ ERROR argument never used | ------- ^ argument never used | | | formatting specifier missing | help: format specifiers use curly braces, consider adding a format specifier | -LL | pub fn main() { println!("🦀%%%{}", 0) } +LL | pub fn main() { println!("🦀%%%{}", 0) } //~ ERROR argument never used | ++ error: aborting due to 1 previous error + diff --git a/tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr b/tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr index 2b18d0193441d..b5c120f939b40 100644 --- a/tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr +++ b/tests/ui/macros/trailing-percent-format-hint-issue-158216.stderr @@ -12,3 +12,4 @@ LL | println!("{x:>8.2}%{}", "foo"); | ++ error: aborting due to 1 previous error + From 356c63f036093b4e6e3a8bf4102c106f84f5e21c Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sun, 21 Jun 2026 17:59:29 -0300 Subject: [PATCH 085/116] Correct issue 92267 UI baseline --- tests/ui/macros/issue-92267.stderr | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/ui/macros/issue-92267.stderr b/tests/ui/macros/issue-92267.stderr index 7bbbb28cdacad..8f8d345f51b5f 100644 --- a/tests/ui/macros/issue-92267.stderr +++ b/tests/ui/macros/issue-92267.stderr @@ -1,15 +1,14 @@ error: argument never used --> $DIR/issue-92267.rs:3:34 | -LL | pub fn main() { println!("🦀%%%", 0) } //~ ERROR argument never used +LL | pub fn main() { println!("🦀%%%", 0) } | ------- ^ argument never used | | | formatting specifier missing | help: format specifiers use curly braces, consider adding a format specifier | -LL | pub fn main() { println!("🦀%%%{}", 0) } //~ ERROR argument never used +LL | pub fn main() { println!("🦀%%%{}", 0) } | ++ error: aborting due to 1 previous error - From 2a86b91480a420a5bfcdfc3cbb733fc390ab8e72 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sun, 21 Jun 2026 18:38:02 -0300 Subject: [PATCH 086/116] Update issue 92267 stderr ending --- tests/ui/macros/issue-92267.stderr | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/macros/issue-92267.stderr b/tests/ui/macros/issue-92267.stderr index 8f8d345f51b5f..2318d5d565a1d 100644 --- a/tests/ui/macros/issue-92267.stderr +++ b/tests/ui/macros/issue-92267.stderr @@ -12,3 +12,4 @@ LL | pub fn main() { println!("🦀%%%{}", 0) } | ++ error: aborting due to 1 previous error + From 9b6c684064e3ce89a966836e29573050a8168c85 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 22 Jun 2026 06:00:38 +0000 Subject: [PATCH 087/116] Prepare for merging from rust-lang/rust This updates the rust-version file to 942ac9ce4116d4ea784c9882659372b34978b1f8. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 5bdff8eb64eec..5db47ca8fc59b 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -485ec3fbcc12fa14ef6596dabb125ad710499c9e +942ac9ce4116d4ea784c9882659372b34978b1f8 From b1e1db9ef4b8a9d6b13fc8d05cde358920793857 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Jun 2026 06:55:41 +0000 Subject: [PATCH 088/116] Add tup expr arg unbounded assoc const test and update test with proper expected enum diagnostics --- .../mgca/tuple_expr_arg_bad-issue-151048.rs | 2 +- .../mgca/tuple_expr_arg_bad-issue-151048.stderr | 2 +- .../mgca/tuple_expr_arg_mismatch_type.rs | 2 +- .../mgca/tuple_expr_arg_mismatch_type.stderr | 2 +- .../mgca/tuple_expr_arg_unbounded_assoc_const.rs | 13 +++++++++++++ .../tuple_expr_arg_unbounded_assoc_const.stderr | 8 ++++++++ 6 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.rs create mode 100644 tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.stderr diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs index 4aecd30e86bbb..70b955589d3e7 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs @@ -2,7 +2,7 @@ #![expect(incomplete_features)] struct Y { - stuff: [u8; { ([1, 2], 3, [4, 5]) }], //~ ERROR expected `usize`, found const tuple + stuff: [u8; { ([1, 2], 3, [4, 5]) }], //~ ERROR expected `usize`, found `([1, 2], 3, [4, 5])` } fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr index 468bf703d90d4..aa54a5ae77048 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr @@ -1,4 +1,4 @@ -error: expected `usize`, found const tuple +error: expected `usize`, found `([1, 2], 3, [4, 5])` --> $DIR/tuple_expr_arg_bad-issue-151048.rs:5:19 | LL | stuff: [u8; { ([1, 2], 3, [4, 5]) }], diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs index 95acd66074f6f..608a4af353a5e 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs @@ -2,7 +2,7 @@ #![expect(incomplete_features)] pub fn takes_nested_tuple() { - takes_nested_tuple::<{ () }> //~ ERROR expected `u32`, found const tuple + takes_nested_tuple::<{ () }> //~ ERROR expected `u32`, found `()` } fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr index dfbd294951fdc..d8314a6b6a57e 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr @@ -1,4 +1,4 @@ -error: expected `u32`, found const tuple +error: expected `u32`, found `()` --> $DIR/tuple_expr_arg_mismatch_type.rs:5:28 | LL | takes_nested_tuple::<{ () }> diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.rs new file mode 100644 index 0000000000000..f844dae5c8220 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.rs @@ -0,0 +1,13 @@ +#![feature(min_generic_const_args, adt_const_params)] + +// Regression test for an ICE in privacy checking while walking the `T` qself +// of `T::ASSOC` inside a tuple const argument. + +fn takes_tuple() {} + +fn generic_caller() { + takes_tuple::<{ (N, T::ASSOC) }>; + //~^ ERROR expected `()`, found `(N, T::ASSOC)` +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.stderr new file mode 100644 index 0000000000000..3af04db14b60b --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_unbounded_assoc_const.stderr @@ -0,0 +1,8 @@ +error: expected `()`, found `(N, T::ASSOC)` + --> $DIR/tuple_expr_arg_unbounded_assoc_const.rs:9:21 + | +LL | takes_tuple::<{ (N, T::ASSOC) }>; + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From f0cf39249c1aa48fd18c3e957ff7a7e32059bdf8 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Jun 2026 06:59:09 +0000 Subject: [PATCH 089/116] typo fix from hid_id to hir_id --- compiler/rustc_hir_typeck/src/writeback.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index ba5b55b43049f..58139a5e3480a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -348,7 +348,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) { intravisit::walk_ty(self, hir_ty); // If there are type checking errors, Type privacy pass will stop, - // so we may not get the type from hid_id, see #104513 + // so we may not get the type from hir_id, see #104513 if let Some(ty) = self.fcx.node_ty_opt(hir_ty.hir_id) { let ty = self.resolve(ty, &hir_ty.span); self.write_ty_to_typeck_results(hir_ty.hir_id, ty); From cd8c4d06e229c16566972e94b6b95ee82f6a217c Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Jun 2026 07:12:32 +0000 Subject: [PATCH 090/116] Check the target and souce tuple elements mismatch duing const_arg_tup lowering --- .../src/hir_ty_lowering/mod.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 80c1106780ca7..21fe7f70e2359 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2518,15 +2518,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Const<'tcx> { let tcx = self.tcx(); + let found_tuple = || { + tcx.sess + .source_map() + .span_to_snippet(span) + .map(|snippet| format!("`{snippet}`")) + .unwrap_or_else(|_| "const tuple".to_string()) + }; + let tys = match ty.kind() { ty::Tuple(tys) => tys, ty::Error(e) => return Const::new_error(tcx, *e), _ => { - let e = tcx.dcx().span_err(span, format!("expected `{}`, found const tuple", ty)); + let e = + tcx.dcx().span_err(span, format!("expected `{}`, found {}", ty, found_tuple())); return Const::new_error(tcx, e); } }; + if exprs.len() != tys.len() { + let e = tcx.dcx().span_err(span, format!("expected `{}`, found {}", ty, found_tuple())); + return Const::new_error(tcx, e); + } + let exprs = exprs .iter() .zip(tys.iter()) From 40aef82197cbf4153f478ff082d04409fd421e26 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 17 Jun 2026 18:12:55 +0200 Subject: [PATCH 091/116] c-variadic: test that we use equality up to free lifetimes --- src/tools/miri/tests/pass/c-variadic.rs | 15 +++++ tests/ui/consts/const-eval/c-variadic-fail.rs | 10 +++ .../consts/const-eval/c-variadic-fail.stderr | 66 +++++++++++++------ 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/src/tools/miri/tests/pass/c-variadic.rs b/src/tools/miri/tests/pass/c-variadic.rs index 4179c7090830c..e17d6820c5b0b 100644 --- a/src/tools/miri/tests/pass/c-variadic.rs +++ b/src/tools/miri/tests/pass/c-variadic.rs @@ -106,6 +106,20 @@ fn various_types() { } } +fn equal_up_to_free_lifetime() { + // Types are considered equal up to free lifetimes: `*const &'static str` + // is the same as `*const &'a str`. + // Bound lifetimes (using e.g. `for<'_>`) are different. + #[expect(improper_ctypes_definitions)] + pub unsafe extern "C" fn foo(mut args: ...) -> &'static str { + unsafe { *args.next_arg::<*const &'static str>() } + } + + let data = String::from("abc"); + let x: &str = data.as_str(); + assert_eq!(unsafe { foo(&raw const x) }, "abc"); +} + fn clone() { if cfg!(force_intrinsic_fallback) { // Skip this test when we use the fallback bodies. The fallback body does @@ -170,6 +184,7 @@ fn main() { forward_by_ref(); nested(); various_types(); + equal_up_to_free_lifetime(); clone(); clone_and_advance(); } diff --git a/tests/ui/consts/const-eval/c-variadic-fail.rs b/tests/ui/consts/const-eval/c-variadic-fail.rs index 063e1af88cc7c..087e649af95f9 100644 --- a/tests/ui/consts/const-eval/c-variadic-fail.rs +++ b/tests/ui/consts/const-eval/c-variadic-fail.rs @@ -119,6 +119,15 @@ unsafe fn read_cast_pointer() { //~^ ERROR requested `*const u8` is incompatible with next argument of type `usize` } +unsafe fn read_cast_lifetime() { + // The types are equal up to free lifetimes. + const { read_as::<*const &'static i32>(std::ptr::dangling::<&i32>()) }; + + // Bound lifetimes do matter. + const { read_as::<*const fn(&'static ())>(std::ptr::dangling:: fn(&'a ())>()) }; + //~^ ERROR va_arg type mismatch: requested `*const fn(&())` is incompatible with next argument of type `*const for<'a> fn(&'a ())` +} + fn use_after_free() { const unsafe extern "C" fn helper(ap: ...) -> [u8; size_of::()] { unsafe { std::mem::transmute(ap) } @@ -196,6 +205,7 @@ fn main() { read_too_many(); read_cast_numeric(); read_cast_pointer(); + read_cast_lifetime(); manual_copy_read(); manual_copy_drop(); manual_copy_forget(); diff --git a/tests/ui/consts/const-eval/c-variadic-fail.stderr b/tests/ui/consts/const-eval/c-variadic-fail.stderr index a184a3ab435e7..c1f9ed0fb398a 100644 --- a/tests/ui/consts/const-eval/c-variadic-fail.stderr +++ b/tests/ui/consts/const-eval/c-variadic-fail.stderr @@ -390,8 +390,36 @@ LL | const { read_as::<*const u8>(1usize) }; | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0080]: va_arg type mismatch: requested `*const fn(&())` is incompatible with next argument of type `*const for<'a> fn(&'a ())` + --> $DIR/c-variadic-fail.rs:127:13 + | +LL | const { read_as::<*const fn(&'static ())>(std::ptr::dangling:: fn(&'a ())>()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_lifetime::{constant#1}` failed inside this call + | +note: inside `read_as::<*const fn(&())>` + --> $DIR/c-variadic-fail.rs:37:5 + | +LL | ap.next_arg::() + | ^^^^^^^^^^^^^^^^^^ +note: inside `VaList::<'_>::next_arg::<*const fn(&())>` + --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL + +note: erroneous constant encountered + --> $DIR/c-variadic-fail.rs:127:5 + | +LL | const { read_as::<*const fn(&'static ())>(std::ptr::dangling:: fn(&'a ())>()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant encountered + --> $DIR/c-variadic-fail.rs:127:5 + | +LL | const { read_as::<*const fn(&'static ())>(std::ptr::dangling:: fn(&'a ())>()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is dangling - --> $DIR/c-variadic-fail.rs:131:13 + --> $DIR/c-variadic-fail.rs:140:13 | LL | ap.next_arg::(); | ^^^^^^^^^^^^^^^^^^^^ evaluation of `use_after_free::{constant#0}` failed inside this call @@ -400,7 +428,7 @@ note: inside `VaList::<'_>::next_arg::` --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:127:5 + --> $DIR/c-variadic-fail.rs:136:5 | LL | / const { LL | | unsafe { @@ -411,7 +439,7 @@ LL | | }; | |_____^ note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:127:5 + --> $DIR/c-variadic-fail.rs:136:5 | LL | / const { LL | | unsafe { @@ -424,13 +452,13 @@ LL | | }; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0080]: using ALLOC1 as variable argument list pointer but it does not point to a variable argument list - --> $DIR/c-variadic-fail.rs:153:22 + --> $DIR/c-variadic-fail.rs:162:22 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_drop::{constant#0}` failed inside this call | note: inside `manual_copy_drop::helper` - --> $DIR/c-variadic-fail.rs:150:9 + --> $DIR/c-variadic-fail.rs:159:9 | LL | drop(ap); | ^^^^^^^^ @@ -442,13 +470,13 @@ note: inside ` as Drop>::drop` --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:153:5 + --> $DIR/c-variadic-fail.rs:162:5 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:153:5 + --> $DIR/c-variadic-fail.rs:162:5 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -456,13 +484,13 @@ LL | const { unsafe { helper(1, 2, 3) } }; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0080]: using ALLOC2 as variable argument list pointer but it does not point to a variable argument list - --> $DIR/c-variadic-fail.rs:169:22 + --> $DIR/c-variadic-fail.rs:178:22 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_forget::{constant#0}` failed inside this call | note: inside `manual_copy_forget::helper` - --> $DIR/c-variadic-fail.rs:166:9 + --> $DIR/c-variadic-fail.rs:175:9 | LL | drop(ap); | ^^^^^^^^ @@ -474,13 +502,13 @@ note: inside ` as Drop>::drop` --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:169:5 + --> $DIR/c-variadic-fail.rs:178:5 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:169:5 + --> $DIR/c-variadic-fail.rs:178:5 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -488,13 +516,13 @@ LL | const { unsafe { helper(1, 2, 3) } }; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0080]: using ALLOC3 as variable argument list pointer but it does not point to a variable argument list - --> $DIR/c-variadic-fail.rs:182:22 + --> $DIR/c-variadic-fail.rs:191:22 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_read::{constant#0}` failed inside this call | note: inside `manual_copy_read::helper` - --> $DIR/c-variadic-fail.rs:179:17 + --> $DIR/c-variadic-fail.rs:188:17 | LL | let _ = ap.next_arg::(); | ^^^^^^^^^^^^^^^^^^^^ @@ -502,13 +530,13 @@ note: inside `VaList::<'_>::next_arg::` --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:182:5 + --> $DIR/c-variadic-fail.rs:191:5 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:182:5 + --> $DIR/c-variadic-fail.rs:191:5 | LL | const { unsafe { helper(1, 2, 3) } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -516,7 +544,7 @@ LL | const { unsafe { helper(1, 2, 3) } }; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer - --> $DIR/c-variadic-fail.rs:190:5 + --> $DIR/c-variadic-fail.rs:199:5 | LL | } | ^ evaluation of `drop_of_invalid::{constant#0}` failed inside this call @@ -527,7 +555,7 @@ note: inside ` as Drop>::drop` --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:187:5 + --> $DIR/c-variadic-fail.rs:196:5 | LL | / const { LL | | let mut invalid: MaybeUninit = MaybeUninit::zeroed(); @@ -536,7 +564,7 @@ LL | | } | |_____^ note: erroneous constant encountered - --> $DIR/c-variadic-fail.rs:187:5 + --> $DIR/c-variadic-fail.rs:196:5 | LL | / const { LL | | let mut invalid: MaybeUninit = MaybeUninit::zeroed(); @@ -546,6 +574,6 @@ LL | | } | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 19 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0080`. From 3da461260fb33a4038adf6fd2ee328215b136819 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 22 Jun 2026 16:50:44 +0200 Subject: [PATCH 092/116] norm: fix escaping placeholder check --- compiler/rustc_next_trait_solver/src/normalize.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index 3bf2f64cf8887..675c8be873f0d 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -121,24 +121,21 @@ where alias_term: AliasTerm, has_escaping: HasEscapingBoundVars, ) -> Result, NoSolution> { - let current_universe = self.infcx.universe(); - self.infcx.create_next_universe(); - let (normalized, ambig_goal) = (self.normalize)(alias_term)?; // Return ambiguous higher ranked alias as is, if // - it contains escaping vars, and - // - the normalized term contains infer vars newly created - // in the normalization above. - // The problem is that they may be resolved to types - // referencing the temporary placeholders. + // - the normalized term contains infer vars which may mention + // temporary placeholders after we've already mapped them back + // to bound vars. // - // We can normalize the ambiguous alias again after the binder is instantiated. + // We can normalize the ambiguous alias again after the binder is instantiated + // or once we've made further inference progress. if ambig_goal.is_some() && has_escaping == HasEscapingBoundVars::Yes { let mut visitor = MaxUniverse::new(self.infcx); normalized.visit_with(&mut visitor); let max_universe = visitor.max_universe(); - if current_universe.cannot_name(max_universe) { + if max_universe.can_name(self.universes.first().unwrap().unwrap()) { return Ok(None); } } From f99e8948be12104fbe57d25b81d6d8b4cf9ae5ee Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 21 Jun 2026 20:38:41 +0200 Subject: [PATCH 093/116] Move target checking for `#[lang]` to the attribute parser --- .../src/attributes/rustc_internal.rs | 25 ++++++++++++++++++- .../rustc_attr_parsing/src/diagnostics.rs | 24 ++++++++++++++++-- compiler/rustc_passes/src/diagnostics.rs | 20 --------------- compiler/rustc_passes/src/lang_items.rs | 23 +++++++---------- compiler/rustc_passes/src/weak_lang_items.rs | 24 ++++++++---------- tests/ui/error-codes/E0264.rs | 4 +-- tests/ui/error-codes/E0264.stderr | 6 ++--- .../panic-handler-wrong-location.rs | 2 +- .../panic-handler-wrong-location.stderr | 11 ++++---- 9 files changed, 77 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 6552c9de7c5a5..07e24329ccea1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -12,6 +12,7 @@ use rustc_span::Symbol; use super::prelude::*; use super::util::parse_single_integer; use crate::diagnostics; +use crate::diagnostics::{LangItemOnIncorrectTarget, UnknownExternLangItem}; use crate::session_diagnostics::{ AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem, }; @@ -576,6 +577,28 @@ impl SingleAttributeParser for LangParser { cx.emit_err(UnknownLangItem { span: cx.attr_span, name }); return None; }; + + // Only weak lang items may be applied to foreign items + if [Target::ForeignFn, Target::ForeignStatic, Target::ForeignTy, Target::ForeignMod] + .contains(&cx.target) + && !lang_item.is_weak() + { + cx.emit_err(UnknownExternLangItem { span: cx.attr_span, lang_item: lang_item.name() }); + return None; + } + + // Check the target + if cx.target != lang_item.target() + && !(cx.target == Target::ForeignFn && lang_item == LangItem::PanicImpl) + { + cx.emit_err(LangItemOnIncorrectTarget { + span: cx.attr_span, + name, + expected_target: lang_item.target(), + actual_target: cx.target, + }); + return None; + } Some(AttributeKind::Lang(lang_item)) } } @@ -599,7 +622,7 @@ pub(crate) struct PanicHandlerParser; impl NoArgsAttributeParser for PanicHandlerParser { const PATH: &[Symbol] = &[sym::panic_handler]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes` + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Lang(LangItem::PanicImpl); } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index b22fe88a4de3d..cf6a773bd1394 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1,5 +1,6 @@ -use rustc_errors::{Applicability, DiagArgValue, E0232, MultiSpan}; -use rustc_hir::AttrPath; +use rustc_errors::E0264; +use rustc_errors::{Applicability, DiagArgValue, E0232, E0718, MultiSpan}; +use rustc_hir::{AttrPath, Target}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -801,3 +802,22 @@ pub(crate) struct UnsafeAttribute { pub attr_path: AttrPath, pub note: &'static str, } + +#[derive(Diagnostic)] +#[diag("`{$name}` lang item must be applied to a {$expected_target}", code = E0718)] +pub(crate) struct LangItemOnIncorrectTarget { + #[primary_span] + #[label("attribute should be applied to a {$expected_target}, not a {$actual_target}")] + pub span: Span, + pub name: Symbol, + pub expected_target: Target, + pub actual_target: Target, +} + +#[derive(Diagnostic)] +#[diag("unknown external lang item: `{$lang_item}`", code = E0264)] +pub(crate) struct UnknownExternLangItem { + #[primary_span] + pub span: Span, + pub lang_item: Symbol, +} diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index f6c4b0cf77d12..a4ba014d2f6aa 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -5,7 +5,6 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, msg, }; -use rustc_hir::Target; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; @@ -326,14 +325,6 @@ pub(crate) struct DeprecatedAnnotationHasNoEffect { pub span: Span, } -#[derive(Diagnostic)] -#[diag("unknown external lang item: `{$lang_item}`", code = E0264)] -pub(crate) struct UnknownExternLangItem { - #[primary_span] - pub span: Span, - pub lang_item: Symbol, -} - #[derive(Diagnostic)] #[diag("`#[panic_handler]` function required, but not found")] pub(crate) struct MissingPanicHandler; @@ -398,17 +389,6 @@ pub(crate) struct LangItemWithTargetFeature { pub sig_span: Span, } -#[derive(Diagnostic)] -#[diag("`{$name}` lang item must be applied to a {$expected_target}", code = E0718)] -pub(crate) struct LangItemOnIncorrectTarget { - #[primary_span] - #[label("attribute should be applied to a {$expected_target}, not a {$actual_target}")] - pub span: Span, - pub name: Symbol, - pub expected_target: Target, - pub actual_target: Target, -} - #[derive(Diagnostic)] #[diag("duplicate diagnostic item in crate `{$crate_name}`: `{$name}`")] pub(crate) struct DuplicateDiagnosticItemInCrate { diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 53fb6888ddcd8..1686b4d595933 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -18,9 +18,7 @@ use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::cstore::ExternCrate; use rustc_span::{Span, Symbol, sym}; -use crate::diagnostics::{ - DuplicateLangItem, IncorrectCrateType, IncorrectTarget, LangItemOnIncorrectTarget, -}; +use crate::diagnostics::{DuplicateLangItem, IncorrectCrateType, IncorrectTarget}; use crate::weak_lang_items; pub(crate) enum Duplicate { @@ -63,8 +61,14 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { ) { if let Some((name, attr_span)) = extract_ast(attrs) { match LangItem::from_name(name) { - // Known lang item with attribute on correct target. - Some(lang_item) if actual_target == lang_item.target() => { + // Known lang item + Some(lang_item) => { + if actual_target != lang_item.target() { + self.tcx + .dcx() + .delayed_bug("lang item target is checked in attribute parser"); + return; + } self.collect_item_extended( lang_item, def_id, @@ -74,15 +78,6 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { actual_target, ); } - // Known lang item with attribute on incorrect target. - Some(lang_item) => { - self.tcx.dcx().emit_err(LangItemOnIncorrectTarget { - span: attr_span, - name, - expected_target: lang_item.target(), - actual_target, - }); - } // Unknown lang item. _ => { self.tcx.dcx().delayed_bug("unknown lang item"); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index b42b27ec74184..98e0c0f241b4c 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use crate::diagnostics::{ - MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, UnknownExternLangItem, + MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, }; use crate::lang_items::extract_ast; @@ -28,27 +28,23 @@ pub(crate) fn check_crate( items.missing.push(LangItem::EhPersonality); } - visit::Visitor::visit_crate(&mut WeakLangItemVisitor { tcx, items }, krate); + visit::Visitor::visit_crate(&mut WeakLangItemVisitor { items }, krate); verify(tcx, items); } -struct WeakLangItemVisitor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, +struct WeakLangItemVisitor<'a> { items: &'a mut lang_items::LanguageItems, } -impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> { +impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_> { fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { - if let Some((lang_item, _)) = extract_ast(&i.attrs) { - if let Some(item) = LangItem::from_name(lang_item) - && item.is_weak() - { - if self.items.get(item).is_none() { - self.items.missing.push(item); - } - } else { - self.tcx.dcx().emit_err(UnknownExternLangItem { span: i.span, lang_item }); + if let Some((lang_item, _)) = extract_ast(&i.attrs) + && let Some(item) = LangItem::from_name(lang_item) + && item.is_weak() + { + if self.items.get(item).is_none() { + self.items.missing.push(item); } } } diff --git a/tests/ui/error-codes/E0264.rs b/tests/ui/error-codes/E0264.rs index 855644796ed45..ef3c8a1c3acd1 100644 --- a/tests/ui/error-codes/E0264.rs +++ b/tests/ui/error-codes/E0264.rs @@ -1,8 +1,8 @@ #![feature(lang_items)] extern "C" { - #[lang = "copy"] - fn copy(); //~ ERROR E0264 + #[lang = "copy"] //~ ERROR E0264 + fn copy(); } fn main() {} diff --git a/tests/ui/error-codes/E0264.stderr b/tests/ui/error-codes/E0264.stderr index 6442f42e689d6..b15ba468aa1a7 100644 --- a/tests/ui/error-codes/E0264.stderr +++ b/tests/ui/error-codes/E0264.stderr @@ -1,8 +1,8 @@ error[E0264]: unknown external lang item: `copy` - --> $DIR/E0264.rs:5:5 + --> $DIR/E0264.rs:4:5 | -LL | fn copy(); - | ^^^^^^^^^^ +LL | #[lang = "copy"] + | ^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.rs b/tests/ui/panic-handler/panic-handler-wrong-location.rs index 8fff7067136e2..22f6b6e724890 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.rs +++ b/tests/ui/panic-handler/panic-handler-wrong-location.rs @@ -3,7 +3,7 @@ #![no_std] #![no_main] -#[panic_handler] //~ ERROR `panic_impl` lang item must be applied to a function +#[panic_handler] //~ ERROR attribute cannot be used on statics static X: u32 = 42; //~? ERROR `#[panic_handler]` function required, but not found diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.stderr b/tests/ui/panic-handler/panic-handler-wrong-location.stderr index 9b361bf8d603f..7af0a4326d9a0 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.stderr +++ b/tests/ui/panic-handler/panic-handler-wrong-location.stderr @@ -1,11 +1,12 @@ -error[E0718]: `panic_impl` lang item must be applied to a function +error: `#[panic_handler]` function required, but not found + +error: `#[panic_handler]` attribute cannot be used on statics --> $DIR/panic-handler-wrong-location.rs:6:1 | LL | #[panic_handler] - | ^^^^^^^^^^^^^^^^ attribute should be applied to a function, not a static - -error: `#[panic_handler]` function required, but not found + | ^^^^^^^^^^^^^^^^ + | + = help: `#[panic_handler]` can only be applied to functions error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0718`. From b8758a32d7ab334fd6406861e66189c7eed92e26 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 21 Jun 2026 20:49:22 +0200 Subject: [PATCH 094/116] Add lifetime parameter to `AllowedTargets` --- .../src/attributes/allow_unstable.rs | 6 +- .../src/attributes/autodiff.rs | 2 +- .../rustc_attr_parsing/src/attributes/body.rs | 3 +- .../src/attributes/cfi_encoding.rs | 2 +- .../src/attributes/codegen_attrs.rs | 36 ++++---- .../src/attributes/confusables.rs | 2 +- .../src/attributes/crate_level.rs | 40 ++++----- .../src/attributes/debugger.rs | 2 +- .../src/attributes/deprecation.rs | 2 +- .../attributes/diagnostic/do_not_recommend.rs | 2 +- .../src/attributes/diagnostic/on_const.rs | 2 +- .../src/attributes/diagnostic/on_move.rs | 2 +- .../attributes/diagnostic/on_type_error.rs | 2 +- .../attributes/diagnostic/on_unimplemented.rs | 2 +- .../src/attributes/diagnostic/on_unknown.rs | 2 +- .../diagnostic/on_unmatched_args.rs | 2 +- .../rustc_attr_parsing/src/attributes/doc.rs | 4 +- .../src/attributes/dummy.rs | 2 +- .../src/attributes/inline.rs | 4 +- .../src/attributes/instruction_set.rs | 2 +- .../src/attributes/link_attrs.rs | 24 ++--- .../src/attributes/lint_helpers.rs | 10 +-- .../src/attributes/loop_match.rs | 4 +- .../src/attributes/macro_attrs.rs | 15 ++-- .../rustc_attr_parsing/src/attributes/mod.rs | 14 +-- .../src/attributes/must_not_suspend.rs | 2 +- .../src/attributes/must_use.rs | 2 +- .../src/attributes/no_implicit_prelude.rs | 2 +- .../src/attributes/no_link.rs | 2 +- .../src/attributes/non_exhaustive.rs | 2 +- .../rustc_attr_parsing/src/attributes/path.rs | 2 +- .../src/attributes/pin_v2.rs | 2 +- .../src/attributes/proc_macro_attrs.rs | 11 +-- .../src/attributes/prototype.rs | 2 +- .../rustc_attr_parsing/src/attributes/repr.rs | 6 +- .../src/attributes/rustc_allocator.rs | 10 +-- .../src/attributes/rustc_dump.rs | 29 ++++--- .../src/attributes/rustc_internal.rs | 87 ++++++++++--------- .../src/attributes/semantics.rs | 4 +- .../src/attributes/splat.rs | 2 +- .../src/attributes/stability.rs | 12 +-- .../src/attributes/test_attrs.rs | 16 ++-- .../src/attributes/traits.rs | 20 ++--- .../src/attributes/transparency.rs | 3 +- .../src/attributes/unroll.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 2 +- .../rustc_attr_parsing/src/diagnostics.rs | 3 +- .../rustc_attr_parsing/src/target_checking.rs | 12 +-- compiler/rustc_passes/src/weak_lang_items.rs | 4 +- 49 files changed, 216 insertions(+), 211 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 3e10e5e70b2c2..119b67b353cb8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -11,7 +11,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { type Item = (Symbol, Span); const CONVERT: ConvertFn = |items, span| AttributeKind::AllowInternalUnstable(items, span); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::MacroDef), Allow(Target::Fn), Warn(Target::Field), @@ -36,7 +36,7 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { type Item = (Symbol, Span); const CONVERT: ConvertFn = |items, _| AttributeKind::UnstableFeatureBound(items); const STABILITY: AttributeStability = unstable!(staged_api); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Impl { of_trait: true }), Allow(Target::Trait), @@ -59,7 +59,7 @@ impl CombineAttributeParser for RustcAllowConstFnUnstableParser { type Item = Symbol; const CONVERT: ConvertFn = |items, first_span| AttributeKind::RustcAllowConstFnUnstable(items, first_span); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), diff --git a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs index 890cb33d08720..78ed4ff46d997 100644 --- a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs +++ b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs @@ -19,7 +19,7 @@ pub(crate) struct RustcAutodiffParser; impl SingleAttributeParser for RustcAutodiffParser { const PATH: &[Symbol] = &[sym::rustc_autodiff]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs index b817d9346dafc..f3a4f04e02ae8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/body.rs +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -8,7 +8,8 @@ pub(crate) struct CoroutineParser; impl NoArgsAttributeParser for CoroutineParser { const PATH: &[Symbol] = &[sym::coroutine]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::Closure)]); const STABILITY: AttributeStability = unstable!(coroutines); const CREATE: fn(rustc_span::Span) -> AttributeKind = |_| AttributeKind::Coroutine; } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs index 2e7644fc70551..8a9102a78e25b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs @@ -4,7 +4,7 @@ use super::prelude::*; pub(crate) struct CfiEncodingParser; impl SingleAttributeParser for CfiEncodingParser { const PATH: &[Symbol] = &[sym::cfi_encoding]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Struct), Allow(Target::ForeignTy), Allow(Target::Enum), diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 155df43c813e8..7beee7e341b90 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -18,7 +18,7 @@ pub(crate) struct OptimizeParser; impl SingleAttributeParser for OptimizeParser { const PATH: &[Symbol] = &[sym::optimize]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Closure), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -51,7 +51,7 @@ pub(crate) struct ColdParser; impl NoArgsAttributeParser for ColdParser { const PATH: &[Symbol] = &[sym::cold]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), @@ -67,7 +67,7 @@ pub(crate) struct CoverageParser; impl SingleAttributeParser for CoverageParser { const PATH: &[Symbol] = &[sym::coverage]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Closure), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -114,7 +114,7 @@ impl SingleAttributeParser for ExportNameParser { note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them", unsafe_since: Some(Edition2024), }; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Static), Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), @@ -151,7 +151,7 @@ pub(crate) struct RustcObjcClassParser; impl SingleAttributeParser for RustcObjcClassParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName"); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -179,7 +179,7 @@ pub(crate) struct RustcObjcSelectorParser; impl SingleAttributeParser for RustcObjcSelectorParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName"); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -226,7 +226,7 @@ impl AttributeParser for NakedParser { note: "the `#[naked]` attribute adds the safety obligation that the function's body must respect the function’s calling convention, uphold its signature, and either return or diverge (i.e., not fall through past the end of the assembly code).", unsafe_since: None, }; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -334,7 +334,7 @@ pub(crate) struct TrackCallerParser; impl NoArgsAttributeParser for TrackCallerParser { const PATH: &[Symbol] = &[sym::track_caller]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -359,7 +359,7 @@ impl NoArgsAttributeParser for NoMangleParser { note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them", unsafe_since: Some(Edition2024), }; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Fn), Allow(Target::Static), Allow(Target::Method(MethodKind::Inherent)), @@ -462,7 +462,7 @@ impl AttributeParser for UsedParser { } }, )]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { @@ -533,7 +533,7 @@ impl CombineAttributeParser for TargetFeatureParser { parse_tf_attribute(cx, args) } - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -561,7 +561,7 @@ impl CombineAttributeParser for ForceTargetFeatureParser { was_forced: true, }; const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -581,7 +581,7 @@ pub(crate) struct InstrumentFnParser; impl SingleAttributeParser for InstrumentFnParser { const PATH: &[Symbol] = &[sym::instrument_fn]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -619,7 +619,7 @@ pub(crate) struct SanitizeParser; impl SingleAttributeParser for SanitizeParser { const PATH: &[Symbol] = &[sym::sanitize]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Closure), Allow(Target::Method(MethodKind::Inherent)), @@ -751,7 +751,7 @@ pub(crate) struct ThreadLocalParser; impl NoArgsAttributeParser for ThreadLocalParser { const PATH: &[Symbol] = &[sym::thread_local]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]); const STABILITY: AttributeStability = unstable!(thread_local); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal; @@ -761,7 +761,7 @@ pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser; impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser { const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis; } @@ -770,7 +770,7 @@ pub(crate) struct RustcEiiForeignItemParser; impl NoArgsAttributeParser for RustcEiiForeignItemParser { const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]); const STABILITY: AttributeStability = unstable!(eii_internals); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem; @@ -780,7 +780,7 @@ pub(crate) struct PatchableFunctionEntryParser; impl SingleAttributeParser for PatchableFunctionEntryParser { const PATH: &[Symbol] = &[sym::patchable_function_entry]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]); const STABILITY: AttributeStability = unstable!(patchable_function_entry); diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 3b2115eeb01e2..091566012d158 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -32,7 +32,7 @@ impl AttributeParser for ConfusablesParser { this.first_span.get_or_insert(cx.attr_span); }, )]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index eb78bc0775f6b..f99cb61be42c2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -13,7 +13,7 @@ impl SingleAttributeParser for CrateNameParser { const PATH: &[Symbol] = &[sym::crate_name]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = AttributeStability::Stable; @@ -32,7 +32,7 @@ impl CombineAttributeParser for CrateTypeParser { const PATH: &[Symbol] = &[sym::crate_type]; type Item = CrateType; const CONVERT: ConvertFn = |items, _| AttributeKind::CrateType(items); - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html"); @@ -76,7 +76,7 @@ impl SingleAttributeParser for RecursionLimitParser { const PATH: &[Symbol] = &[sym::recursion_limit]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = AttributeStability::Stable; @@ -92,7 +92,7 @@ pub(crate) struct MoveSizeLimitParser; impl SingleAttributeParser for MoveSizeLimitParser { const PATH: &[Symbol] = &[sym::move_size_limit]; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(large_assignments); fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { @@ -108,7 +108,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { const PATH: &[Symbol] = &[sym::type_length_limit]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = AttributeStability::Stable; @@ -124,7 +124,7 @@ pub(crate) struct PatternComplexityLimitParser; impl SingleAttributeParser for PatternComplexityLimitParser { const PATH: &[Symbol] = &[sym::pattern_complexity_limit]; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!( rustc_attrs, "the `#[pattern_complexity_limit]` attribute is used for rustc unit tests" @@ -141,7 +141,7 @@ pub(crate) struct NoCoreParser; impl NoArgsAttributeParser for NoCoreParser { const PATH: &[Symbol] = &[sym::no_core]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(no_core); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoCore; } @@ -151,7 +151,7 @@ pub(crate) struct NoStdParser; impl NoArgsAttributeParser for NoStdParser { const PATH: &[Symbol] = &[sym::no_std]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoStd; @@ -162,7 +162,7 @@ pub(crate) struct NoMainParser; impl NoArgsAttributeParser for NoMainParser { const PATH: &[Symbol] = &[sym::no_main]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain; @@ -172,7 +172,7 @@ pub(crate) struct RustcCoherenceIsCoreParser; impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCoherenceIsCore; } @@ -182,7 +182,7 @@ pub(crate) struct WindowsSubsystemParser; impl SingleAttributeParser for WindowsSubsystemParser { const PATH: &[Symbol] = &[sym::windows_subsystem]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); const STABILITY: AttributeStability = AttributeStability::Stable; @@ -210,7 +210,7 @@ pub(crate) struct PanicRuntimeParser; impl NoArgsAttributeParser for PanicRuntimeParser { const PATH: &[Symbol] = &[sym::panic_runtime]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(panic_runtime); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime; } @@ -219,7 +219,7 @@ pub(crate) struct NeedsPanicRuntimeParser; impl NoArgsAttributeParser for NeedsPanicRuntimeParser { const PATH: &[Symbol] = &[sym::needs_panic_runtime]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(needs_panic_runtime); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime; } @@ -228,7 +228,7 @@ pub(crate) struct ProfilerRuntimeParser; impl NoArgsAttributeParser for ProfilerRuntimeParser { const PATH: &[Symbol] = &[sym::profiler_runtime]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(profiler_runtime); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime; } @@ -238,7 +238,7 @@ pub(crate) struct NoBuiltinsParser; impl NoArgsAttributeParser for NoBuiltinsParser { const PATH: &[Symbol] = &[sym::no_builtins]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins; @@ -248,7 +248,7 @@ pub(crate) struct RustcPreserveUbChecksParser; impl NoArgsAttributeParser for RustcPreserveUbChecksParser { const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks; } @@ -257,7 +257,7 @@ pub(crate) struct RustcNoImplicitBoundsParser; impl NoArgsAttributeParser for RustcNoImplicitBoundsParser { const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds; } @@ -266,7 +266,7 @@ pub(crate) struct DefaultLibAllocatorParser; impl NoArgsAttributeParser for DefaultLibAllocatorParser { const PATH: &[Symbol] = &[sym::default_lib_allocator]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(allocator_internals); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator; } @@ -277,7 +277,7 @@ impl CombineAttributeParser for FeatureParser { const PATH: &[Symbol] = &[sym::feature]; type Item = Ident; const CONVERT: ConvertFn = AttributeKind::Feature; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]); const STABILITY: AttributeStability = AttributeStability::Stable; @@ -323,7 +323,7 @@ impl CombineAttributeParser for RegisterToolParser { const PATH: &[Symbol] = &[sym::register_tool]; type Item = Ident; const CONVERT: ConvertFn = |tools, _span| AttributeKind::RegisterTool(tools); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(List: &["tool1, tool2, ..."]); const STABILITY: AttributeStability = unstable!(register_tool); diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 8d2cff35905ed..b514235a48eca 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -7,7 +7,7 @@ pub(crate) struct DebuggerVisualizerParser; impl CombineAttributeParser for DebuggerVisualizerParser { const PATH: &[Symbol] = &[sym::debugger_visualizer]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!( List: &[r#"natvis_file = "...", gdb_script_file = "...""#], diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index ee3734bf19541..d401aafed7bec 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -32,7 +32,7 @@ fn get( pub(crate) struct DeprecatedParser; impl SingleAttributeParser for DeprecatedParser { const PATH: &[Symbol] = &[sym::deprecated]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Fn), Allow(Target::Mod), Allow(Target::Struct), diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs index 85708273a409b..250326db42bb7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs @@ -16,7 +16,7 @@ impl SingleAttributeParser for DoNotRecommendParser { const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; // "Allowed" on any target, noop on all but trait impls - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Impl { of_trait: true })]); const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */); const STABILITY: AttributeStability = AttributeStability::Stable; diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index dc8260ae944ef..a7b71b9080dca 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -37,7 +37,7 @@ impl AttributeParser for OnConstParser { // "Allowed" on all targets; noop on anything but non-const trait impls; // this linted on in parser. - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ // FIXME(mejrs) no constness field on `Target`, // so non-constness is still checked in check_attr.rs Allow(Target::Impl { of_trait: true }), diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index ec77ede4127f5..1c8b3418fa746 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -43,7 +43,7 @@ impl AttributeParser for OnMoveParser { }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Enum), Allow(Target::Struct), Allow(Target::Union), diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs index d5636b23a09b1..89cae4b7c55f1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_type_error.rs @@ -42,7 +42,7 @@ impl AttributeParser for OnTypeErrorParser { }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Enum), Allow(Target::Struct), Allow(Target::Union), diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs index 86a96f7093587..057d243c6d123 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs @@ -45,7 +45,7 @@ impl AttributeParser for OnUnimplementedParser { }, ), ]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Trait)]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index fc05ae9150d15..bfa26d993b17e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -40,7 +40,7 @@ impl AttributeParser for OnUnknownParser { }, )]; // "Allowed" for all targets, but noop for all but use statements. - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Use), Allow(Target::Mod), Allow(Target::Crate), diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs index 44975cd49c93f..18f980bfebbe8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatched_args.rs @@ -33,7 +33,7 @@ impl AttributeParser for OnUnmatchedArgsParser { }, )]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::MacroDef)]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index e91ab584bcf47..988df2b200f86 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -706,8 +706,8 @@ impl AttributeParser for DocParser { }, )]; // FIXME: Currently emitted from 2 different places, generating duplicated warnings. - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); - // const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(ALL_TARGETS); + // const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ // Allow(Target::ExternCrate), // Allow(Target::Use), // Allow(Target::Static), diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index d436c7f232ec7..83984d48919b7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -12,7 +12,7 @@ pub(crate) struct RustcDummyParser; impl SingleAttributeParser for RustcDummyParser { const PATH: &[Symbol] = &[sym::rustc_dummy]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::ManuallyChecked; + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::ManuallyChecked; const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really const STABILITY: AttributeStability = unstable!(rustc_attrs, "the `#[rustc_dummy]` attribute is used for rustc unit tests"); diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 84b880202a9e6..80328e1c8ef96 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -13,7 +13,7 @@ pub(crate) struct InlineParser; impl SingleAttributeParser for InlineParser { const PATH: &[Symbol] = &[sym::inline]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -66,7 +66,7 @@ pub(crate) struct RustcForceInlineParser; impl SingleAttributeParser for RustcForceInlineParser { const PATH: &[Symbol] = &[sym::rustc_force_inline]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), ]); diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 612d5d33d94e0..3a4bb926f759c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -8,7 +8,7 @@ pub(crate) struct InstructionSetParser; impl SingleAttributeParser for InstructionSetParser { const PATH: &[Symbol] = &[sym::instruction_set]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Fn), Allow(Target::Closure), Allow(Target::Method(MethodKind::Inherent)), diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index f260863840080..2357d6846935c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -26,7 +26,7 @@ pub(crate) struct LinkNameParser; impl SingleAttributeParser for LinkNameParser { const PATH: &[Symbol] = &[sym::link_name]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::ForeignFn), Allow(Target::ForeignStatic), ]); @@ -70,7 +70,7 @@ impl CombineAttributeParser for LinkParser { r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#, r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#, ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"); - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::ForeignMod)]); const STABILITY: AttributeStability = AttributeStability::Stable; @@ -494,7 +494,7 @@ impl SingleAttributeParser for LinkSectionParser { unsafe_since: Some(Edition2024), }; const STABILITY: AttributeStability = AttributeStability::Stable; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Static), Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), @@ -535,7 +535,7 @@ impl SingleAttributeParser for LinkSectionParser { pub(crate) struct ExportStableParser; impl NoArgsAttributeParser for ExportStableParser { const PATH: &[Symbol] = &[sym::export_stable]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Struct), @@ -558,7 +558,8 @@ impl NoArgsAttributeParser for FfiConstParser { note: "`#[ffi_const]` functions shall have no effects except for its return value, which can only depend on the values of the function parameters, and is not affected by changes to the observable state of the program.", unsafe_since: None, }; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const STABILITY: AttributeStability = unstable!(ffi_const); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::FfiConst; } @@ -570,7 +571,8 @@ impl NoArgsAttributeParser for FfiPureParser { note: "`#[ffi_pure]` functions shall have no effects except for its return value, which shall not change across two consecutive function calls with the same parameters.", unsafe_since: None, }; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const STABILITY: AttributeStability = unstable!(ffi_pure); const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure; } @@ -578,7 +580,7 @@ impl NoArgsAttributeParser for FfiPureParser { pub(crate) struct RustcStdInternalSymbolParser; impl NoArgsAttributeParser for RustcStdInternalSymbolParser { const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::ForeignFn), Allow(Target::Static), @@ -592,7 +594,7 @@ pub(crate) struct LinkOrdinalParser; impl SingleAttributeParser for LinkOrdinalParser { const PATH: &[Symbol] = &[sym::link_ordinal]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::ForeignFn), Allow(Target::ForeignStatic), Warn(Target::MacroCall), @@ -632,7 +634,7 @@ pub(crate) struct LinkageParser; impl SingleAttributeParser for LinkageParser { const PATH: &[Symbol] = &[sym::linkage]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -708,7 +710,7 @@ pub(crate) struct NeedsAllocatorParser; impl NoArgsAttributeParser for NeedsAllocatorParser { const PATH: &[Symbol] = &[sym::needs_allocator]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(allocator_internals); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator; } @@ -717,7 +719,7 @@ pub(crate) struct CompilerBuiltinsParser; impl NoArgsAttributeParser for CompilerBuiltinsParser { const PATH: &[Symbol] = &[sym::compiler_builtins]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(compiler_builtins); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins; } diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 75a07e868129e..38afeea07794a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -5,7 +5,7 @@ use super::prelude::*; pub(crate) struct RustcAsPtrParser; impl NoArgsAttributeParser for RustcAsPtrParser { const PATH: &[Symbol] = &[sym::rustc_as_ptr]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -19,7 +19,7 @@ impl NoArgsAttributeParser for RustcAsPtrParser { pub(crate) struct RustcPubTransparentParser; impl NoArgsAttributeParser for RustcPubTransparentParser { const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Struct), Allow(Target::Enum), Allow(Target::Union), @@ -31,7 +31,7 @@ impl NoArgsAttributeParser for RustcPubTransparentParser { pub(crate) struct RustcPassByValueParser; impl NoArgsAttributeParser for RustcPassByValueParser { const PATH: &[Symbol] = &[sym::rustc_pass_by_value]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Struct), Allow(Target::Enum), Allow(Target::TyAlias), @@ -43,7 +43,7 @@ impl NoArgsAttributeParser for RustcPassByValueParser { pub(crate) struct RustcShouldNotBeCalledOnConstItemsParser; impl NoArgsAttributeParser for RustcShouldNotBeCalledOnConstItemsParser { const PATH: &[Symbol] = &[sym::rustc_should_not_be_called_on_const_items]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), ]); @@ -55,7 +55,7 @@ pub(crate) struct AutomaticallyDerivedParser; impl NoArgsAttributeParser for AutomaticallyDerivedParser { const PATH: &[Symbol] = &[sym::automatically_derived]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Impl { of_trait: true }), Error(Target::Crate), Error(Target::WherePredicate), diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs index 06c3cd286a06e..e46d2edaa49ba 100644 --- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -5,7 +5,7 @@ use super::prelude::*; pub(crate) struct LoopMatchParser; impl NoArgsAttributeParser for LoopMatchParser { const PATH: &[Symbol] = &[sym::loop_match]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Loop)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Loop)]); const STABILITY: AttributeStability = unstable!(loop_match); const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch; } @@ -13,7 +13,7 @@ impl NoArgsAttributeParser for LoopMatchParser { pub(crate) struct ConstContinueParser; impl NoArgsAttributeParser for ConstContinueParser { const PATH: &[Symbol] = &[sym::const_continue]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Break)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Break)]); const STABILITY: AttributeStability = unstable!(loop_match); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue; } diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 8ad202bad3d84..f49a7e674d560 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -8,7 +8,7 @@ pub(crate) struct MacroEscapeParser; impl NoArgsAttributeParser for MacroEscapeParser { const PATH: &[Symbol] = &[sym::macro_escape]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = MACRO_USE_ALLOWED_TARGETS; const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::MacroEscape; } @@ -32,7 +32,7 @@ const MACRO_USE_TEMPLATE: AttributeTemplate = template!( Word, List: &["name1, name2, ..."], "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute" ); -const MACRO_USE_ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ +const MACRO_USE_ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Mod), Allow(Target::ExternCrate), Error(Target::WherePredicate), @@ -106,7 +106,7 @@ impl AttributeParser for MacroUseParser { } }, )]; - const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = MACRO_USE_ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state }) @@ -118,7 +118,7 @@ pub(crate) struct AllowInternalUnsafeParser; impl NoArgsAttributeParser for AllowInternalUnsafeParser { const PATH: &[Symbol] = &[sym::allow_internal_unsafe]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::MacroDef), Warn(Target::Field), @@ -134,7 +134,7 @@ impl SingleAttributeParser for MacroExportParser { const PATH: &[Symbol] = &[sym::macro_export]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const TEMPLATE: AttributeTemplate = template!(Word, List: &["local_inner_macros"]); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::MacroDef), Error(Target::WherePredicate), Error(Target::Crate), @@ -174,7 +174,8 @@ impl SingleAttributeParser for CollapseDebugInfoParser { List: &["no", "external", "yes"], "https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute" ); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const STABILITY: AttributeStability = AttributeStability::Stable; fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { @@ -204,7 +205,7 @@ pub(crate) struct RustcProcMacroDeclsParser; impl NoArgsAttributeParser for RustcProcMacroDeclsParser { const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Static)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls; } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 5c64e9f2eaed6..17aaa6ddf9333 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -105,7 +105,7 @@ pub(crate) trait AttributeParser: Default + 'static { /// /// If an attribute has this symbol, the `accept` function will be called on it. const ATTRIBUTES: AcceptMapping; - const ALLOWED_TARGETS: AllowedTargets; + const ALLOWED_TARGETS: AllowedTargets<'_>; const SAFETY: AttributeSafety = AttributeSafety::Normal; /// The parser has gotten a chance to accept the attributes on an item, @@ -140,7 +140,7 @@ pub(crate) trait SingleAttributeParser: 'static { const SAFETY: AttributeSafety = AttributeSafety::Normal; const STABILITY: AttributeStability; - const ALLOWED_TARGETS: AllowedTargets; + const ALLOWED_TARGETS: AllowedTargets<'_>; /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; @@ -174,7 +174,7 @@ impl AttributeParser for Single { } }, )]; - const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS; const SAFETY: AttributeSafety = T::SAFETY; fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { @@ -252,7 +252,7 @@ pub enum AttributeSafety { pub(crate) trait NoArgsAttributeParser: 'static { const PATH: &[Symbol]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets; + const ALLOWED_TARGETS: AllowedTargets<'_>; const SAFETY: AttributeSafety = AttributeSafety::Normal; const STABILITY: AttributeStability; @@ -273,7 +273,7 @@ impl SingleAttributeParser for WithoutArgs { const ON_DUPLICATE: OnDuplicate = T::ON_DUPLICATE; const SAFETY: AttributeSafety = T::SAFETY; const STABILITY: AttributeStability = T::STABILITY; - const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { @@ -303,7 +303,7 @@ pub(crate) trait CombineAttributeParser: 'static { const SAFETY: AttributeSafety = AttributeSafety::Normal; const STABILITY: AttributeStability; - const ALLOWED_TARGETS: AllowedTargets; + const ALLOWED_TARGETS: AllowedTargets<'_>; /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; @@ -342,7 +342,7 @@ impl AttributeParser for Combine { group.first_span.get_or_insert(cx.attr_span); group.items.extend(T::extend(cx, args)) })]; - const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS; const SAFETY: AttributeSafety = T::SAFETY; fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs index 25fdd5fb3e086..c7c302dd9ee2d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs @@ -6,7 +6,7 @@ pub(crate) struct MustNotSuspendParser; impl SingleAttributeParser for MustNotSuspendParser { const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Struct), Allow(Target::Enum), Allow(Target::Union), diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index ae41efd769ed0..62e75a2e7afd9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -7,7 +7,7 @@ pub(crate) struct MustUseParser; impl SingleAttributeParser for MustUseParser { const PATH: &[Symbol] = &[sym::must_use]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[ Allow(Target::Fn), Allow(Target::Enum), Allow(Target::Struct), diff --git a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs index ce172bc41beee..34ceca9092036 100644 --- a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs @@ -7,7 +7,7 @@ pub(crate) struct NoImplicitPreludeParser; impl NoArgsAttributeParser for NoImplicitPreludeParser { const PATH: &[rustc_span::Symbol] = &[sym::no_implicit_prelude]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Allow(Target::Crate)]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoImplicitPrelude; diff --git a/compiler/rustc_attr_parsing/src/attributes/no_link.rs b/compiler/rustc_attr_parsing/src/attributes/no_link.rs index d067db5df81e6..772ebb6b34f69 100644 --- a/compiler/rustc_attr_parsing/src/attributes/no_link.rs +++ b/compiler/rustc_attr_parsing/src/attributes/no_link.rs @@ -6,7 +6,7 @@ pub(crate) struct NoLinkParser; impl NoArgsAttributeParser for NoLinkParser { const PATH: &[Symbol] = &[sym::no_link]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::ExternCrate), Warn(Target::Field), Warn(Target::Arm), diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index c4cc47e593a6a..cbbaad445f70f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -12,7 +12,7 @@ pub(crate) struct NonExhaustiveParser; impl NoArgsAttributeParser for NonExhaustiveParser { const PATH: &[Symbol] = &[sym::non_exhaustive]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Enum), Allow(Target::Struct), Allow(Target::Variant), diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index 57114d850dba8..ad4641c4be7f2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -7,7 +7,7 @@ pub(crate) struct PathParser; impl SingleAttributeParser for PathParser { const PATH: &[Symbol] = &[sym::path]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Error(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "file", diff --git a/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs b/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs index ba84b6f8e98c4..59c35690d3c93 100644 --- a/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs +++ b/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs @@ -12,7 +12,7 @@ pub(crate) struct PinV2Parser; impl NoArgsAttributeParser for PinV2Parser { const PATH: &[Symbol] = &[sym::pin_v2]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Enum), Allow(Target::Struct), Allow(Target::Union), diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 887eb668d65ab..8b2720d2a9ca5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -3,13 +3,13 @@ use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS; use super::prelude::*; -const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets = +const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate), Warn(Target::MacroCall)]); pub(crate) struct ProcMacroParser; impl NoArgsAttributeParser for ProcMacroParser { const PATH: &[Symbol] = &[sym::proc_macro]; - const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = PROC_MACRO_ALLOWED_TARGETS; const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProcMacro; } @@ -17,7 +17,7 @@ impl NoArgsAttributeParser for ProcMacroParser { pub(crate) struct ProcMacroAttributeParser; impl NoArgsAttributeParser for ProcMacroAttributeParser { const PATH: &[Symbol] = &[sym::proc_macro_attribute]; - const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = PROC_MACRO_ALLOWED_TARGETS; const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProcMacroAttribute; } @@ -25,7 +25,7 @@ impl NoArgsAttributeParser for ProcMacroAttributeParser { pub(crate) struct ProcMacroDeriveParser; impl SingleAttributeParser for ProcMacroDeriveParser { const PATH: &[Symbol] = &[sym::proc_macro_derive]; - const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = PROC_MACRO_ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!( List: &["TraitName", "TraitName, attributes(name1, name2, ...)"], "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros" @@ -44,7 +44,8 @@ impl SingleAttributeParser for ProcMacroDeriveParser { pub(crate) struct RustcBuiltinMacroParser; impl SingleAttributeParser for RustcBuiltinMacroParser { const PATH: &[Symbol] = &[sym::rustc_builtin_macro]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]); const STABILITY: AttributeStability = unstable!(rustc_attrs); diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index ddc40e62a7e8e..a41010395e7c1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -18,7 +18,7 @@ impl SingleAttributeParser for CustomMirParser { const PATH: &[rustc_span::Symbol] = &[sym::custom_mir]; const STABILITY: AttributeStability = unstable!(custom_mir); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index b6e63de1a2095..bf03d87942651 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -63,7 +63,7 @@ impl CombineAttributeParser for ReprParser { reprs } - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::ManuallyChecked; + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::ManuallyChecked; const STABILITY: AttributeStability = AttributeStability::Stable; } @@ -306,7 +306,7 @@ impl RustcAlignParser { impl AttributeParser for RustcAlignParser { const ATTRIBUTES: AcceptMapping = &[(Self::PATH, Self::TEMPLATE, unstable!(fn_align), Self::parse)]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -336,7 +336,7 @@ impl RustcAlignStaticParser { impl AttributeParser for RustcAlignStaticParser { const ATTRIBUTES: AcceptMapping = &[(Self::PATH, Self::TEMPLATE, unstable!(static_align), Self::parse)]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs index cacf98bef6e93..467289d78da9b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -6,7 +6,7 @@ pub(crate) struct RustcAllocatorParser; impl NoArgsAttributeParser for RustcAllocatorParser { const PATH: &[Symbol] = &[sym::rustc_allocator]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator; @@ -16,7 +16,7 @@ pub(crate) struct RustcAllocatorZeroedParser; impl NoArgsAttributeParser for RustcAllocatorZeroedParser { const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed; @@ -26,7 +26,7 @@ pub(crate) struct RustcAllocatorZeroedVariantParser; impl SingleAttributeParser for RustcAllocatorZeroedVariantParser { const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function"); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -42,7 +42,7 @@ pub(crate) struct RustcDeallocatorParser; impl NoArgsAttributeParser for RustcDeallocatorParser { const PATH: &[Symbol] = &[sym::rustc_deallocator]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator; @@ -52,7 +52,7 @@ pub(crate) struct RustcReallocatorParser; impl NoArgsAttributeParser for RustcReallocatorParser { const PATH: &[Symbol] = &[sym::rustc_reallocator]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index acd5b465a80fe..0fd3d5d65e3a5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -10,7 +10,7 @@ pub(crate) struct RustcDumpUserArgsParser; impl NoArgsAttributeParser for RustcDumpUserArgsParser { const PATH: &[Symbol] = &[sym::rustc_dump_user_args]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs; } @@ -19,7 +19,7 @@ pub(crate) struct RustcDumpDefParentsParser; impl NoArgsAttributeParser for RustcDumpDefParentsParser { const PATH: &[Symbol] = &[sym::rustc_dump_def_parents]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents; } @@ -28,7 +28,7 @@ pub(crate) struct RustcDumpDefPathParser; impl SingleAttributeParser for RustcDumpDefPathParser { const PATH: &[Symbol] = &[sym::rustc_dump_def_path]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::TraitImpl)), Allow(Target::Method(MethodKind::Inherent)), @@ -49,7 +49,7 @@ pub(crate) struct RustcDumpGenericsParser; impl NoArgsAttributeParser for RustcDumpGenericsParser { const PATH: &[Symbol] = &[sym::rustc_dump_generics]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Struct), Allow(Target::Enum), Allow(Target::Union), @@ -78,7 +78,7 @@ pub(crate) struct RustcDumpHiddenTypeOfOpaquesParser; impl NoArgsAttributeParser for RustcDumpHiddenTypeOfOpaquesParser { const PATH: &[Symbol] = &[sym::rustc_dump_hidden_type_of_opaques]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpHiddenTypeOfOpaques; } @@ -87,7 +87,7 @@ pub(crate) struct RustcDumpInferredOutlivesParser; impl NoArgsAttributeParser for RustcDumpInferredOutlivesParser { const PATH: &[Symbol] = &[sym::rustc_dump_inferred_outlives]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Struct), Allow(Target::Enum), Allow(Target::Union), @@ -101,7 +101,8 @@ pub(crate) struct RustcDumpItemBoundsParser; impl NoArgsAttributeParser for RustcDumpItemBoundsParser { const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::AssocTy)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; } @@ -115,7 +116,7 @@ impl CombineAttributeParser for RustcDumpLayoutParser { const CONVERT: ConvertFn = |items, _| AttributeKind::RustcDumpLayout(items); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Struct), Allow(Target::Enum), Allow(Target::Union), @@ -174,7 +175,7 @@ pub(crate) struct RustcDumpObjectLifetimeDefaultsParser; impl NoArgsAttributeParser for RustcDumpObjectLifetimeDefaultsParser { const PATH: &[Symbol] = &[sym::rustc_dump_object_lifetime_defaults]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::AssocConst), Allow(Target::AssocTy), Allow(Target::Const), @@ -201,7 +202,7 @@ pub(crate) struct RustcDumpPredicatesParser; impl NoArgsAttributeParser for RustcDumpPredicatesParser { const PATH: &[Symbol] = &[sym::rustc_dump_predicates]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::AssocConst), Allow(Target::AssocTy), Allow(Target::Const), @@ -229,7 +230,7 @@ pub(crate) struct RustcDumpSymbolNameParser; impl SingleAttributeParser for RustcDumpSymbolNameParser { const PATH: &[Symbol] = &[sym::rustc_dump_symbol_name]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::TraitImpl)), Allow(Target::Method(MethodKind::Inherent)), @@ -250,7 +251,7 @@ pub(crate) struct RustcDumpVariancesParser; impl NoArgsAttributeParser for RustcDumpVariancesParser { const PATH: &[Symbol] = &[sym::rustc_dump_variances]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Enum), Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), @@ -271,7 +272,7 @@ pub(crate) struct RustcDumpVariancesOfOpaquesParser; impl NoArgsAttributeParser for RustcDumpVariancesOfOpaquesParser { const PATH: &[Symbol] = &[sym::rustc_dump_variances_of_opaques]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpVariancesOfOpaques; } @@ -280,7 +281,7 @@ pub(crate) struct RustcDumpVtableParser; impl NoArgsAttributeParser for RustcDumpVtableParser { const PATH: &[Symbol] = &[sym::rustc_dump_vtable]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Impl { of_trait: true }), Allow(Target::TyAlias), ]); diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 07e24329ccea1..607c908565d3a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -21,7 +21,7 @@ pub(crate) struct RustcMainParser; impl NoArgsAttributeParser for RustcMainParser { const PATH: &[Symbol] = &[sym::rustc_main]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = unstable!( rustc_attrs, "the `#[rustc_main]` attribute is used internally to specify test entry point function" @@ -33,7 +33,7 @@ pub(crate) struct RustcMustImplementOneOfParser; impl SingleAttributeParser for RustcMustImplementOneOfParser { const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!( rustc_attrs, "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization" @@ -79,7 +79,7 @@ pub(crate) struct RustcNeverReturnsNullPtrParser; impl NoArgsAttributeParser for RustcNeverReturnsNullPtrParser { const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -94,7 +94,7 @@ pub(crate) struct RustcNoImplicitAutorefsParser; impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser { const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -110,7 +110,7 @@ pub(crate) struct RustcLegacyConstGenericsParser; impl SingleAttributeParser for RustcLegacyConstGenericsParser { const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(List: &["N"]); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -150,7 +150,7 @@ pub(crate) struct RustcInheritOverflowChecksParser; impl NoArgsAttributeParser for RustcInheritOverflowChecksParser { const PATH: &[Symbol] = &[sym::rustc_inherit_overflow_checks]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), @@ -164,7 +164,7 @@ pub(crate) struct RustcLintOptDenyFieldAccessParser; impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Field)]); const TEMPLATE: AttributeTemplate = template!(Word); const STABILITY: AttributeStability = unstable!(rustc_attrs); fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { @@ -179,7 +179,7 @@ pub(crate) struct RustcLintOptTyParser; impl NoArgsAttributeParser for RustcLintOptTyParser { const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy; } @@ -306,7 +306,7 @@ impl AttributeParser for RustcCguTestAttributeParser { ), ]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]); fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { @@ -318,7 +318,7 @@ pub(crate) struct RustcDeprecatedSafe2024Parser; impl SingleAttributeParser for RustcDeprecatedSafe2024Parser { const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -348,7 +348,7 @@ pub(crate) struct RustcConversionSuggestionParser; impl NoArgsAttributeParser for RustcConversionSuggestionParser { const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -363,7 +363,8 @@ pub(crate) struct RustcCaptureAnalysisParser; impl NoArgsAttributeParser for RustcCaptureAnalysisParser { const PATH: &[Symbol] = &[sym::rustc_capture_analysis]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::Closure)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis; } @@ -372,7 +373,7 @@ pub(crate) struct RustcNeverTypeOptionsParser; impl SingleAttributeParser for RustcNeverTypeOptionsParser { const PATH: &[Symbol] = &[sym::rustc_never_type_options]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(List: &[ r#"fallback = "unit", "never", "no""#, r#"diverging_block_default = "unit", "never""#, @@ -445,7 +446,7 @@ pub(crate) struct RustcTrivialFieldReadsParser; impl NoArgsAttributeParser for RustcTrivialFieldReadsParser { const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads; } @@ -454,7 +455,7 @@ pub(crate) struct RustcNoMirInlineParser; impl NoArgsAttributeParser for RustcNoMirInlineParser { const PATH: &[Symbol] = &[sym::rustc_no_mir_inline]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -470,7 +471,7 @@ pub(crate) struct RustcNoWritableParser; impl NoArgsAttributeParser for RustcNoWritableParser { const PATH: &[Symbol] = &[sym::rustc_no_writable]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Closure), Allow(Target::Method(MethodKind::Inherent)), @@ -485,7 +486,7 @@ pub(crate) struct RustcLintQueryInstabilityParser; impl NoArgsAttributeParser for RustcLintQueryInstabilityParser { const PATH: &[Symbol] = &[sym::rustc_lint_query_instability]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -500,7 +501,7 @@ pub(crate) struct RustcRegionsParser; impl NoArgsAttributeParser for RustcRegionsParser { const PATH: &[Symbol] = &[sym::rustc_regions]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -515,7 +516,7 @@ pub(crate) struct RustcLintUntrackedQueryInformationParser; impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationParser { const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), @@ -530,7 +531,7 @@ pub(crate) struct RustcSimdMonomorphizeLaneLimitParser; impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser { const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -544,7 +545,7 @@ pub(crate) struct RustcScalableVectorParser; impl SingleAttributeParser for RustcScalableVectorParser { const PATH: &[Symbol] = &[sym::rustc_scalable_vector]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -566,7 +567,7 @@ pub(crate) struct LangParser; impl SingleAttributeParser for LangParser { const PATH: &[Symbol] = &[sym::lang]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes` + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::ManuallyChecked; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); const STABILITY: AttributeStability = unstable!(lang_items); @@ -607,7 +608,7 @@ pub(crate) struct RustcHasIncoherentInherentImplsParser; impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParser { const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Trait), Allow(Target::Struct), Allow(Target::Enum), @@ -622,7 +623,7 @@ pub(crate) struct PanicHandlerParser; impl NoArgsAttributeParser for PanicHandlerParser { const PATH: &[Symbol] = &[sym::panic_handler]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Lang(LangItem::PanicImpl); } @@ -631,7 +632,7 @@ pub(crate) struct RustcNounwindParser; impl NoArgsAttributeParser for RustcNounwindParser { const PATH: &[Symbol] = &[sym::rustc_nounwind]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::ForeignFn), Allow(Target::Method(MethodKind::Inherent)), @@ -646,7 +647,7 @@ pub(crate) struct RustcOffloadKernelParser; impl NoArgsAttributeParser for RustcOffloadKernelParser { const PATH: &[Symbol] = &[sym::rustc_offload_kernel]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel; } @@ -659,7 +660,7 @@ impl CombineAttributeParser for RustcMirParser { type Item = RustcMirKind; const CONVERT: ConvertFn = |items, _| AttributeKind::RustcMir(items); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), @@ -735,7 +736,7 @@ pub(crate) struct RustcNonConstTraitMethodParser; impl NoArgsAttributeParser for RustcNonConstTraitMethodParser { const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::Trait { body: false })), ]); @@ -754,7 +755,7 @@ impl CombineAttributeParser for RustcCleanParser { type Item = RustcCleanAttribute; const CONVERT: ConvertFn = |items, _| AttributeKind::RustcClean(items); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ // tidy-alphabetical-start Allow(Target::AssocConst), Allow(Target::AssocTy), @@ -847,7 +848,7 @@ pub(crate) struct RustcIfThisChangedParser; impl SingleAttributeParser for RustcIfThisChangedParser { const PATH: &[Symbol] = &[sym::rustc_if_this_changed]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ // tidy-alphabetical-start Allow(Target::AssocConst), Allow(Target::AssocTy), @@ -905,7 +906,7 @@ impl CombineAttributeParser for RustcThenThisWouldNeedParser { const CONVERT: ConvertFn = |items, _span| AttributeKind::RustcThenThisWouldNeed(items); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ // tidy-alphabetical-start Allow(Target::AssocConst), Allow(Target::AssocTy), @@ -952,7 +953,7 @@ pub(crate) struct RustcInsignificantDtorParser; impl NoArgsAttributeParser for RustcInsignificantDtorParser { const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Enum), Allow(Target::Struct), Allow(Target::ForeignTy), @@ -965,7 +966,7 @@ pub(crate) struct RustcEffectiveVisibilityParser; impl NoArgsAttributeParser for RustcEffectiveVisibilityParser { const PATH: &[Symbol] = &[sym::rustc_effective_visibility]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Use), Allow(Target::Static), Allow(Target::Const), @@ -1004,7 +1005,7 @@ pub(crate) struct RustcDiagnosticItemParser; impl SingleAttributeParser for RustcDiagnosticItemParser { const PATH: &[Symbol] = &[sym::rustc_diagnostic_item]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Trait), Allow(Target::Struct), Allow(Target::Enum), @@ -1039,7 +1040,7 @@ pub(crate) struct RustcDoNotConstCheckParser; impl NoArgsAttributeParser for RustcDoNotConstCheckParser { const PATH: &[Symbol] = &[sym::rustc_do_not_const_check]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), @@ -1057,7 +1058,7 @@ pub(crate) struct RustcNonnullOptimizationGuaranteedParser; impl NoArgsAttributeParser for RustcNonnullOptimizationGuaranteedParser { const PATH: &[Symbol] = &[sym::rustc_nonnull_optimization_guaranteed]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const STABILITY: AttributeStability = unstable!( rustc_attrs, "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library", @@ -1070,7 +1071,7 @@ pub(crate) struct RustcStrictCoherenceParser; impl NoArgsAttributeParser for RustcStrictCoherenceParser { const PATH: &[Symbol] = &[sym::rustc_strict_coherence]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Trait), Allow(Target::Struct), Allow(Target::Enum), @@ -1085,7 +1086,7 @@ pub(crate) struct RustcReservationImplParser; impl SingleAttributeParser for RustcReservationImplParser { const PATH: &[Symbol] = &[sym::rustc_reservation_impl]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "reservation message"); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -1102,7 +1103,7 @@ pub(crate) struct PreludeImportParser; impl NoArgsAttributeParser for PreludeImportParser { const PATH: &[Symbol] = &[sym::prelude_import]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Use)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Use)]); const STABILITY: AttributeStability = unstable!(prelude_import); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport; } @@ -1111,7 +1112,7 @@ pub(crate) struct RustcDocPrimitiveParser; impl SingleAttributeParser for RustcDocPrimitiveParser { const PATH: &[Symbol] = &[sym::rustc_doc_primitive]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Mod)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name"); const STABILITY: AttributeStability = unstable!( rustc_attrs, @@ -1130,7 +1131,7 @@ pub(crate) struct RustcIntrinsicParser; impl NoArgsAttributeParser for RustcIntrinsicParser { const PATH: &[Symbol] = &[sym::rustc_intrinsic]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = unstable!(intrinsics); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic; } @@ -1139,7 +1140,7 @@ pub(crate) struct RustcIntrinsicConstStableIndirectParser; impl NoArgsAttributeParser for RustcIntrinsicConstStableIndirectParser { const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect; } @@ -1148,7 +1149,7 @@ pub(crate) struct RustcExhaustiveParser; impl NoArgsAttributeParser for RustcExhaustiveParser { const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Enum)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively; } diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 07c07eb6681df..74b2cc2ffd5a1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -5,7 +5,7 @@ use super::prelude::*; pub(crate) struct MayDangleParser; impl NoArgsAttributeParser for MayDangleParser { const PATH: &[Symbol] = &[sym::may_dangle]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const STABILITY: AttributeStability = unstable!(dropck_eyepatch); const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; } @@ -14,7 +14,7 @@ pub(crate) struct ComptimeParser; impl NoArgsAttributeParser for ComptimeParser { const PATH: &[Symbol] = &[sym::rustc_comptime]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Fn), ]); diff --git a/compiler/rustc_attr_parsing/src/attributes/splat.rs b/compiler/rustc_attr_parsing/src/attributes/splat.rs index 65fc9fb8123f4..ab34021ad7cdf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/splat.rs +++ b/compiler/rustc_attr_parsing/src/attributes/splat.rs @@ -9,7 +9,7 @@ pub(crate) struct SplatParser; impl NoArgsAttributeParser for SplatParser { const PATH: &[Symbol] = &[sym::splat]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Param)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Param)]); const STABILITY: AttributeStability = unstable!(splat, "the `#[splat]` attribute is experimental"); const CREATE: fn(Span) -> AttributeKind = AttributeKind::Splat; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b38bb6d535770..d8dbe167ed175 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -13,7 +13,7 @@ use super::prelude::*; use super::util::parse_version; use crate::session_diagnostics; -const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ +const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Struct), Allow(Target::Enum), @@ -102,7 +102,7 @@ impl AttributeParser for StabilityParser { }, ), ]; - const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = ALLOWED_TARGETS; fn finalize(mut self, cx: &FinalizeContext<'_, '_>) -> Option { if let Some(atum) = self.allowed_through_unstable_modules { @@ -158,7 +158,7 @@ impl AttributeParser for BodyStabilityParser { } }, )]; - const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; + const ALLOWED_TARGETS: AllowedTargets<'_> = ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { let (stability, span) = self.stability?; @@ -171,7 +171,7 @@ pub(crate) struct RustcConstStableIndirectParser; impl NoArgsAttributeParser for RustcConstStableIndirectParser { const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), ]); @@ -233,7 +233,7 @@ impl AttributeParser for ConstStabilityParser { this.promotable = true; }), ]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), @@ -460,7 +460,7 @@ pub(crate) struct UnstableRemovedParser; impl CombineAttributeParser for UnstableRemovedParser { type Item = UnstableRemovedFeature; const PATH: &[Symbol] = &[sym::unstable_removed]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(List: &[r#"feature = "name", reason = "...", link = "...", since = "version""#]); const STABILITY: AttributeStability = unstable!(staged_api); diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 00e113f171715..8905591bdba5a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -9,7 +9,7 @@ pub(crate) struct IgnoreParser; impl SingleAttributeParser for IgnoreParser { const PATH: &[Symbol] = &[sym::ignore]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); const TEMPLATE: AttributeTemplate = template!( Word, NameValueStr: "reason", @@ -51,7 +51,7 @@ pub(crate) struct ShouldPanicParser; impl SingleAttributeParser for ShouldPanicParser { const PATH: &[Symbol] = &[sym::should_panic]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); const TEMPLATE: AttributeTemplate = template!( Word, List: &[r#"expected = "reason""#], NameValueStr: "reason", @@ -83,7 +83,7 @@ pub(crate) struct ReexportTestHarnessMainParser; impl SingleAttributeParser for ReexportTestHarnessMainParser { const PATH: &[Symbol] = &[sym::reexport_test_harness_main]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); const STABILITY: AttributeStability = unstable!(custom_test_frameworks); @@ -105,7 +105,7 @@ pub(crate) struct RustcAbiParser; impl SingleAttributeParser for RustcAbiParser { const PATH: &[Symbol] = &[sym::rustc_abi]; const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::TyAlias), Allow(Target::Fn), Allow(Target::ForeignFn), @@ -150,7 +150,7 @@ pub(crate) struct RustcDelayedBugFromInsideQueryParser; impl NoArgsAttributeParser for RustcDelayedBugFromInsideQueryParser { const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery; } @@ -159,7 +159,7 @@ pub(crate) struct RustcEvaluateWhereClausesParser; impl NoArgsAttributeParser for RustcEvaluateWhereClausesParser { const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), @@ -174,7 +174,7 @@ pub(crate) struct TestRunnerParser; impl SingleAttributeParser for TestRunnerParser { const PATH: &[Symbol] = &[sym::test_runner]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(List: &["path"]); const STABILITY: AttributeStability = unstable!(custom_test_frameworks); @@ -194,7 +194,7 @@ pub(crate) struct RustcTestMarkerParser; impl SingleAttributeParser for RustcTestMarkerParser { const PATH: &[Symbol] = &[sym::rustc_test_marker]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Const), Allow(Target::Fn), Allow(Target::Static), diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 505cdea2477bf..a2348eef975cf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -12,7 +12,7 @@ use crate::target_checking::Policy::{Allow, Warn}; pub(crate) struct RustcSkipDuringMethodDispatchParser; impl SingleAttributeParser for RustcSkipDuringMethodDispatchParser { const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]); const STABILITY: AttributeStability = unstable!(rustc_attrs); @@ -52,7 +52,7 @@ impl SingleAttributeParser for RustcSkipDuringMethodDispatchParser { pub(crate) struct RustcParenSugarParser; impl NoArgsAttributeParser for RustcParenSugarParser { const PATH: &[Symbol] = &[sym::rustc_paren_sugar]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcParenSugar; } @@ -62,7 +62,7 @@ impl NoArgsAttributeParser for RustcParenSugarParser { pub(crate) struct MarkerParser; impl NoArgsAttributeParser for MarkerParser { const PATH: &[Symbol] = &[sym::marker]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Trait), Warn(Target::Field), Warn(Target::Arm), @@ -75,7 +75,7 @@ impl NoArgsAttributeParser for MarkerParser { pub(crate) struct RustcDenyExplicitImplParser; impl NoArgsAttributeParser for RustcDenyExplicitImplParser { const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDenyExplicitImpl; } @@ -83,7 +83,7 @@ impl NoArgsAttributeParser for RustcDenyExplicitImplParser { pub(crate) struct RustcDynIncompatibleTraitParser; impl NoArgsAttributeParser for RustcDynIncompatibleTraitParser { const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait; } @@ -93,7 +93,7 @@ impl NoArgsAttributeParser for RustcDynIncompatibleTraitParser { pub(crate) struct RustcSpecializationTraitParser; impl NoArgsAttributeParser for RustcSpecializationTraitParser { const PATH: &[Symbol] = &[sym::rustc_specialization_trait]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcSpecializationTrait; } @@ -101,7 +101,7 @@ impl NoArgsAttributeParser for RustcSpecializationTraitParser { pub(crate) struct RustcUnsafeSpecializationMarkerParser; impl NoArgsAttributeParser for RustcUnsafeSpecializationMarkerParser { const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcUnsafeSpecializationMarker; } @@ -111,7 +111,7 @@ impl NoArgsAttributeParser for RustcUnsafeSpecializationMarkerParser { pub(crate) struct RustcCoinductiveParser; impl NoArgsAttributeParser for RustcCoinductiveParser { const PATH: &[Symbol] = &[sym::rustc_coinductive]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCoinductive; } @@ -119,7 +119,7 @@ impl NoArgsAttributeParser for RustcCoinductiveParser { pub(crate) struct RustcAllowIncoherentImplParser; impl NoArgsAttributeParser for RustcAllowIncoherentImplParser { const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]); const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl; @@ -128,7 +128,7 @@ impl NoArgsAttributeParser for RustcAllowIncoherentImplParser { pub(crate) struct FundamentalParser; impl NoArgsAttributeParser for FundamentalParser { const PATH: &[Symbol] = &[sym::fundamental]; - const ALLOWED_TARGETS: AllowedTargets = + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct), Allow(Target::Trait)]); const STABILITY: AttributeStability = unstable!(fundamental); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental; diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ad40f30ef418a..7f5cceb501acd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -11,7 +11,8 @@ impl SingleAttributeParser for RustcMacroTransparencyParser { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); const STABILITY: AttributeStability = unstable!(rustc_attrs); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["transparent", "semiopaque", "opaque"]); diff --git a/compiler/rustc_attr_parsing/src/attributes/unroll.rs b/compiler/rustc_attr_parsing/src/attributes/unroll.rs index b10ddcf9dc4fc..50c73ca041cdd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/unroll.rs +++ b/compiler/rustc_attr_parsing/src/attributes/unroll.rs @@ -7,7 +7,7 @@ use super::prelude::*; pub(crate) struct UnrollParser; impl SingleAttributeParser for UnrollParser { const PATH: &[Symbol] = &[sym::unroll]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Loop), Allow(Target::ForLoop), Allow(Target::While), diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 14e443c922711..1595d2f80ddc7 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -85,7 +85,7 @@ pub(super) struct GroupTypeInner { pub(super) struct GroupTypeInnerAccept { pub(super) template: AttributeTemplate, pub(super) accept_fn: AcceptFn, - pub(super) allowed_targets: AllowedTargets, + pub(super) allowed_targets: AllowedTargets<'static>, pub(super) safety: AttributeSafety, pub(super) stability: AttributeStability, pub(super) finalizer: FinalizeFn, diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index cf6a773bd1394..f2201efe0507e 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1,5 +1,4 @@ -use rustc_errors::E0264; -use rustc_errors::{Applicability, DiagArgValue, E0232, E0718, MultiSpan}; +use rustc_errors::{Applicability, DiagArgValue, E0232, E0264, E0718, MultiSpan}; use rustc_hir::{AttrPath, Target}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 9903c6aa68d01..04f5c2ea39f70 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -16,9 +16,9 @@ use crate::target_checking::Policy::Allow; use crate::{AttributeParser, ShouldEmit}; #[derive(Debug)] -pub(crate) enum AllowedTargets { - AllowList(&'static [Policy]), - AllowListWarnRest(&'static [Policy]), +pub(crate) enum AllowedTargets<'a> { + AllowList(&'a [Policy]), + AllowListWarnRest(&'a [Policy]), /// This is useful for argument-dependent target checking. /// If debug assertions are enabled, /// this emits a delayed bug if the `cx.check_target(...)` method is not called during attribute parsing. @@ -31,7 +31,7 @@ pub(crate) enum AllowedResult { Error, } -impl AllowedTargets { +impl AllowedTargets<'_> { pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult { match self { AllowedTargets::AllowList(list) => { @@ -94,7 +94,7 @@ pub(crate) enum Policy { impl<'sess> AttributeParser<'sess> { pub(crate) fn check_target( - allowed_targets: &AllowedTargets, + allowed_targets: &AllowedTargets<'_>, attribute_args: &'static str, cx: &mut AcceptContext<'_, 'sess>, ) { @@ -444,7 +444,7 @@ impl<'f, 'sess> AcceptContext<'f, 'sess> { pub(crate) fn check_target( &mut self, attribute_args: &'static str, - allowed_targets: &AllowedTargets, + allowed_targets: &AllowedTargets<'_>, ) { self.ignore_target_checks(); AttributeParser::check_target(allowed_targets, attribute_args, self); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 98e0c0f241b4c..50730b852455c 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -9,9 +9,7 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::diagnostics::{ - MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, -}; +use crate::diagnostics::{MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd}; use crate::lang_items::extract_ast; /// Checks the crate for usage of weak lang items, returning a vector of all the From 9ad6dbf24ff30bde68c58b537c30526762ad6615 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 21 Jun 2026 21:08:31 +0200 Subject: [PATCH 095/116] Use `AllowedTargets::ManuallyChecked` for `LangParser` --- .../src/attributes/rustc_internal.rs | 20 ++++++++----------- .../rustc_attr_parsing/src/diagnostics.rs | 15 ++------------ .../src/session_diagnostics.rs | 2 +- .../rustc_attr_parsing/src/target_checking.rs | 8 ++++---- .../src/error_codes/E0718.md | 4 +++- tests/ui/error-codes/E0718.rs | 2 +- tests/ui/error-codes/E0718.stderr | 7 ++++--- 7 files changed, 23 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 607c908565d3a..d4e15b8964ff7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -12,7 +12,7 @@ use rustc_span::Symbol; use super::prelude::*; use super::util::parse_single_integer; use crate::diagnostics; -use crate::diagnostics::{LangItemOnIncorrectTarget, UnknownExternLangItem}; +use crate::diagnostics::UnknownExternLangItem; use crate::session_diagnostics::{ AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem, }; @@ -589,17 +589,13 @@ impl SingleAttributeParser for LangParser { } // Check the target - if cx.target != lang_item.target() - && !(cx.target == Target::ForeignFn && lang_item == LangItem::PanicImpl) - { - cx.emit_err(LangItemOnIncorrectTarget { - span: cx.attr_span, - name, - expected_target: lang_item.target(), - actual_target: cx.target, - }); - return None; - } + let allowed_targets: &[_] = if lang_item == LangItem::PanicImpl { + &[Allow(Target::Fn), Allow(Target::ForeignFn)] + } else { + &[Allow(lang_item.target())] + }; + cx.check_target(&format!(" = \"{name}\""), &AllowedTargets::AllowList(allowed_targets)); + Some(AttributeKind::Lang(lang_item)) } } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index f2201efe0507e..d8b7144aa01ba 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1,5 +1,5 @@ -use rustc_errors::{Applicability, DiagArgValue, E0232, E0264, E0718, MultiSpan}; -use rustc_hir::{AttrPath, Target}; +use rustc_errors::{Applicability, DiagArgValue, E0232, E0264, MultiSpan}; +use rustc_hir::AttrPath; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -802,17 +802,6 @@ pub(crate) struct UnsafeAttribute { pub note: &'static str, } -#[derive(Diagnostic)] -#[diag("`{$name}` lang item must be applied to a {$expected_target}", code = E0718)] -pub(crate) struct LangItemOnIncorrectTarget { - #[primary_span] - #[label("attribute should be applied to a {$expected_target}, not a {$actual_target}")] - pub span: Span, - pub name: Symbol, - pub expected_target: Target, - pub actual_target: Target, -} - #[derive(Diagnostic)] #[diag("unknown external lang item: `{$lang_item}`", code = E0264)] pub(crate) struct UnknownExternLangItem { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 494824a8393b3..fef6f7d9e5503 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -337,7 +337,7 @@ pub(crate) struct InvalidTarget { pub target: &'static str, pub applied: DiagArgValue, pub only: &'static str, - pub attribute_args: &'static str, + pub attribute_args: String, #[subdiagnostic] pub help: Option, #[warning( diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 04f5c2ea39f70..96737be04f5b2 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -95,7 +95,7 @@ pub(crate) enum Policy { impl<'sess> AttributeParser<'sess> { pub(crate) fn check_target( allowed_targets: &AllowedTargets<'_>, - attribute_args: &'static str, + attribute_args: &str, cx: &mut AcceptContext<'_, 'sess>, ) { if matches!(cx.should_emit, ShouldEmit::Nothing) { @@ -137,7 +137,7 @@ impl<'sess> AttributeParser<'sess> { target: cx.target.plural_name(), only: if only { "only " } else { "" }, applied: DiagArgValue::StrListSepByAnd(applied.into_iter().map(Cow::Owned).collect()), - attribute_args, + attribute_args: attribute_args.to_string(), help: Self::target_checking_help(attribute_args, cx), previously_accepted: matches!(result, AllowedResult::Warn) && !is_diagnostic_attr, on_macro_call: matches!(cx.target, Target::MacroCall), @@ -173,7 +173,7 @@ impl<'sess> AttributeParser<'sess> { } fn target_checking_help( - attribute_args: &'static str, + attribute_args: &str, cx: &AcceptContext<'_, '_>, ) -> Option { match &*cx.attr_path.segments { @@ -443,7 +443,7 @@ fn filter_targets( impl<'f, 'sess> AcceptContext<'f, 'sess> { pub(crate) fn check_target( &mut self, - attribute_args: &'static str, + attribute_args: &str, allowed_targets: &AllowedTargets<'_>, ) { self.ignore_target_checks(); diff --git a/compiler/rustc_error_codes/src/error_codes/E0718.md b/compiler/rustc_error_codes/src/error_codes/E0718.md index 1fe62ecf1f4e0..2ecf3081d2ed6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0718.md +++ b/compiler/rustc_error_codes/src/error_codes/E0718.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + A `#[lang = ".."]` attribute was placed on the wrong item type. Erroneous code example: -```compile_fail,E0718 +```compile_fail #![feature(lang_items)] #[lang = "owned_box"] diff --git a/tests/ui/error-codes/E0718.rs b/tests/ui/error-codes/E0718.rs index 358bc348ec76d..87e366c91a609 100644 --- a/tests/ui/error-codes/E0718.rs +++ b/tests/ui/error-codes/E0718.rs @@ -1,7 +1,7 @@ #![feature(lang_items)] // Box is expected to be a struct, so this will error. -#[lang = "owned_box"] //~ ERROR lang item must be applied to a struct +#[lang = "owned_box"] //~ ERROR `#[lang = "owned_box"]` attribute cannot be used on statics static X: u32 = 42; fn main() {} diff --git a/tests/ui/error-codes/E0718.stderr b/tests/ui/error-codes/E0718.stderr index e7784d193ba7b..873c714df8c2f 100644 --- a/tests/ui/error-codes/E0718.stderr +++ b/tests/ui/error-codes/E0718.stderr @@ -1,9 +1,10 @@ -error[E0718]: `owned_box` lang item must be applied to a struct +error: `#[lang = "owned_box"]` attribute cannot be used on statics --> $DIR/E0718.rs:4:1 | LL | #[lang = "owned_box"] - | ^^^^^^^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[lang = "owned_box"]` can only be applied to structs error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0718`. From 68632812fe6be9b70f0ae945e74a274ef80b8517 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Sun, 21 Jun 2026 12:58:34 +0200 Subject: [PATCH 096/116] Split `resolve_ident_in_module_non_globs_unadjusted` into local and external `module` variants. --- compiler/rustc_resolve/src/ident.rs | 103 ++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 2e69405811db4..86d740a93f651 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -23,9 +23,9 @@ use crate::late::{ use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingKey, CmResolver, Decl, DeclKind, - Determinacy, Finalize, IdentKey, ImportKind, ImportSummary, LateDecl, LocalModule, Module, - ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, Res, ResolutionError, - Resolver, Scope, ScopeSet, Segment, Stage, Symbol, Used, diagnostics, + Determinacy, ExternModule, Finalize, IdentKey, ImportKind, ImportSummary, LateDecl, + LocalModule, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, + Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, Symbol, Used, diagnostics, }; #[derive(Copy, Clone)] @@ -608,21 +608,36 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let decl = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( - module, - ident, - orig_ident_span, - ns, - adjusted_parent_scope, - if matches!(scope_set, ScopeSet::Module(..)) { - Shadowing::Unrestricted - } else { - Shadowing::Restricted - }, - adjusted_finalize, - ignore_decl, - ignore_import, - ); + let shadowing = if matches!(scope_set, ScopeSet::Module(..)) { + Shadowing::Unrestricted + } else { + Shadowing::Restricted + }; + let decl = if module.is_local() { + self.reborrow().resolve_ident_in_local_module_non_globs_unadjusted( + module.expect_local(), + ident, + orig_ident_span, + ns, + adjusted_parent_scope, + shadowing, + adjusted_finalize, + ignore_decl, + ignore_import, + ) + } else { + self.reborrow().resolve_ident_in_extern_module_non_globs_unadjusted( + module.expect_extern(), + ident, + orig_ident_span, + ns, + adjusted_parent_scope, + shadowing, + adjusted_finalize, + ignore_decl, + ) + }; + match decl { Ok(decl) => { if let Some(lint_id) = derive_fallback_lint_id { @@ -1078,10 +1093,49 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - /// Attempts to resolve `ident` in namespace `ns` of non-glob bindings in `module`. - fn resolve_ident_in_module_non_globs_unadjusted<'r>( + /// Attempts to resolve `ident` in namespace `ns` of non-glob bindings in an external `module`. + fn resolve_ident_in_extern_module_non_globs_unadjusted<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, - module: Module<'ra>, + module: ExternModule<'ra>, + ident: IdentKey, + orig_ident_span: Span, + ns: Namespace, + parent_scope: &ParentScope<'ra>, + shadowing: Shadowing, + finalize: Option, + // This binding should be ignored during in-module resolution, so that we don't get + // "self-confirming" import resolutions during import validation and checking. + ignore_decl: Option>, + ) -> Result, ControlFlow> { + let key = BindingKey::new(ident, ns); + let resolution = + &*self.resolution(module.to_module(), key).ok_or(ControlFlow::Continue(Determined))?; + + let binding = resolution.non_glob_decl.filter(|b| Some(*b) != ignore_decl); + + if let Some(finalize) = finalize { + return self.get_mut().finalize_module_binding( + ident, + orig_ident_span, + binding, + parent_scope, + finalize, + shadowing, + ); + } + + // Items and single imports are not shadowable, if we have one, then it's determined. + if let Some(binding) = binding { + let accessible = self.is_accessible_from(binding.vis(), parent_scope.module); + return if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) }; + } + Err(ControlFlow::Continue(Determined)) + } + + /// Attempts to resolve `ident` in namespace `ns` of non-glob bindings in a local `module`. + fn resolve_ident_in_local_module_non_globs_unadjusted<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, + module: LocalModule<'ra>, ident: IdentKey, orig_ident_span: Span, ns: Namespace, @@ -1098,7 +1152,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // doesn't need to be mutable. It will fail when there is a cycle of imports, and without // the exclusive access infinite recursion will crash the compiler with stack overflow. let resolution = &*self - .resolution_or_default(module, key, orig_ident_span) + .resolution_or_default(module.to_module(), key, orig_ident_span) .try_borrow_mut_unchecked() .map_err(|_| ControlFlow::Continue(Determined))?; @@ -1121,11 +1175,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) }; } - // In extern modules everything is determined from the start. - if !module.is_local() { - return Err(ControlFlow::Continue(Determined)); - }; - // Check if one of single imports can still define the name, block if it can. if self.reborrow().single_import_can_define_name( &resolution, From 0eb146cbab32a8082c2b43df7abaf6ef1113b42d Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 18 Jun 2026 22:27:27 +0000 Subject: [PATCH 097/116] Extract all instance shim variants into new `ShimKind` enum They tend to have similar handling -- e.g., they should be the only input to the `mir_shims` query -- so it's cleaner to group them together. This will also make potential future refactorings easier, such as only carrying `GenericArgsRef` for instances that actually use it (e.g., `Item`) but not others (e.g., `CloneShim`). Many of the shim variants still have `Shim` at the end of their names. To make the refactoring easier and keep the diff clean, I will trim those suffixes off in the next commit. --- .../rustc_codegen_cranelift/src/abi/mod.rs | 6 +- .../rustc_codegen_cranelift/src/constant.rs | 2 +- .../src/back/symbol_export.rs | 18 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../rustc_const_eval/src/interpret/call.rs | 26 +- .../rustc_const_eval/src/interpret/step.rs | 2 +- .../src/middle/codegen_fn_attrs.rs | 11 +- .../src/middle/exported_symbols.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 8 +- compiler/rustc_middle/src/mir/pretty.rs | 8 +- compiler/rustc_middle/src/mir/visit.rs | 30 +-- compiler/rustc_middle/src/mono.rs | 30 +-- compiler/rustc_middle/src/queries.rs | 4 +- compiler/rustc_middle/src/query/keys.rs | 6 + compiler/rustc_middle/src/ty/instance.rs | 237 +++++++++++------- compiler/rustc_middle/src/ty/mod.rs | 21 +- compiler/rustc_middle/src/ty/print/mod.rs | 57 +++-- .../rustc_mir_transform/src/coroutine/drop.rs | 2 +- .../rustc_mir_transform/src/coroutine/mod.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 33 +-- .../rustc_mir_transform/src/inline/cycle.rs | 26 +- compiler/rustc_mir_transform/src/shim.rs | 88 +++---- .../src/shim/async_destructor_ctor.rs | 20 +- compiler/rustc_monomorphize/src/collector.rs | 34 +-- .../rustc_monomorphize/src/partitioning.rs | 60 ++--- .../src/unstable/convert/stable/ty.rs | 13 +- .../rustc_public_bridge/src/context/impls.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 7 +- .../rustc_sanitizers/src/kcfi/typeid/mod.rs | 5 +- compiler/rustc_symbol_mangling/src/legacy.rs | 21 +- compiler/rustc_symbol_mangling/src/v0.rs | 32 ++- compiler/rustc_ty_utils/src/abi.rs | 40 +-- compiler/rustc_ty_utils/src/instance.rs | 59 +++-- 34 files changed, 502 insertions(+), 416 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 0eb493036ce51..8f965a5ef7b12 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -16,9 +16,9 @@ use rustc_abi::{CanonAbi, ExternAbi, X86Call}; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{ShimKind, TypeVisitableExt}; use rustc_session::Session; use rustc_span::Spanned; use rustc_target::callconv::{FnAbi, PassMode}; @@ -467,7 +467,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( } // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, // it is `func returning noop future` - InstanceKind::DropGlue(_, None) => { + InstanceKind::Shim(ShimKind::DropGlue(_, None)) => { // empty drop glue - a nop. let dest = target.expect("Non terminating drop_in_place_real???"); let ret_block = fx.get_block(dest); @@ -725,7 +725,7 @@ pub(crate) fn codegen_drop<'tcx>( let ret_block = fx.get_block(target); // AsyncDropGlueCtorShim can't be here - if let ty::InstanceKind::DropGlue(_, None) = drop_instance.def { + if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None)) = drop_instance.def { // we don't actually need to drop anything fx.bcx.ins().jump(ret_block, &[]); } else { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c986666f9c46e..a83bfd1cbad42 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -53,7 +53,7 @@ pub(crate) fn codegen_tls_ref<'tcx>( ) -> CValue<'tcx> { let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceKind::ThreadLocalShim(def_id), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), args: ty::GenericArgs::empty(), }; let func_ref = fx.get_function_ref(instance); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 014fd5cf3a0e5..40d5c3b07059f 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -11,7 +11,9 @@ use rustc_middle::middle::exported_symbols::{ ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; use rustc_middle::query::LocalCrate; -use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, GenericArgKind, GenericArgsRef, Instance, ShimKind, SymbolName, Ty, TyCtxt, +}; use rustc_middle::util::Providers; use rustc_session::config::CrateType; use rustc_span::Span; @@ -332,7 +334,10 @@ fn exported_generic_symbols_provider_local<'tcx>( )); } } - MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => { + MonoItem::Fn(Instance { + def: InstanceKind::Shim(ShimKind::DropGlue(_, Some(ty))), + args, + }) => { // A little sanity-check assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty))); @@ -356,7 +361,7 @@ fn exported_generic_symbols_provider_local<'tcx>( } } MonoItem::Fn(Instance { - def: InstanceKind::AsyncDropGlueCtorShim(_, ty), + def: InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(_, ty)), args, }) => { // A little sanity-check @@ -371,7 +376,10 @@ fn exported_generic_symbols_provider_local<'tcx>( }, )); } - MonoItem::Fn(Instance { def: InstanceKind::AsyncDropGlue(def, ty), args: _ }) => { + MonoItem::Fn(Instance { + def: InstanceKind::Shim(ShimKind::AsyncDropGlue(def, ty)), + args: _, + }) => { symbols.push(( ExportedSymbol::AsyncDropGlue(def, ty), SymbolExportInfo { @@ -578,7 +586,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, ty::Instance { - def: ty::InstanceKind::ThreadLocalShim(def_id), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), args: ty::GenericArgs::empty(), }, instantiating_crate, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d4932adeda1f9..8d8b950a125ea 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -618,7 +618,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = self.monomorphize(ty); let drop_fn = Instance::resolve_drop_glue(bx.tcx(), ty); - if let ty::InstanceKind::DropGlue(_, None) = drop_fn.def { + if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None)) = drop_fn.def { // we don't actually need to drop anything. return helper.funclet_br(self, bx, target, mergeable_succ, &[]); } @@ -934,7 +934,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match instance.def { // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, // it is `func returning noop future` - ty::InstanceKind::DropGlue(_, None) => { + ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None)) => { // Empty drop glue; a no-op. let target = target.unwrap(); return helper.funclet_br(self, bx, target, mergeable_succ, &[]); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index deb8ca12b059d..c1ee7c02e874e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -665,7 +665,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceKind::ThreadLocalShim(def_id), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), args: ty::GenericArgs::empty(), }; let fn_ptr = bx.get_fn_addr(instance); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 85da687d8af37..0236b49e497e4 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -428,7 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Determine whether this is a non-capturing closure. That's relevant as their first // argument can be skipped (and that's the only kind of argument skipping we allow). let is_non_capturing_closure = - (matches!(instance.def, ty::InstanceKind::ClosureOnceShim { .. }) + (matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. })) || self.tcx.is_closure_like(def_id)) && { let arg = &callee_fn_abi.args[0]; @@ -652,18 +652,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } } - ty::InstanceKind::VTableShim(..) - | ty::InstanceKind::ReifyShim(..) - | ty::InstanceKind::ClosureOnceShim { .. } - | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::FnPtrShim(..) - | ty::InstanceKind::DropGlue(..) - | ty::InstanceKind::CloneShim(..) - | ty::InstanceKind::FnPtrAddrShim(..) - | ty::InstanceKind::ThreadLocalShim(..) - | ty::InstanceKind::AsyncDropGlueCtorShim(..) - | ty::InstanceKind::AsyncDropGlue(..) - | ty::InstanceKind::FutureDropPollShim(..) + ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(..)) + | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) | ty::InstanceKind::Item(_) => { // We need MIR for this fn. // Note that this can be an intrinsic, if we are executing its fallback body. diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index b865cafa38647..1aeaaee3a251c 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -607,7 +607,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { enter_trace_span!(M, resolve::resolve_drop_glue, ty = ?place.layout.ty); Instance::resolve_drop_glue(*self.tcx, place.layout.ty) }; - if let ty::InstanceKind::DropGlue(_, None) = instance.def { + if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None)) = instance.def { // This is the branch we enter if and only if the dropped type has no drop glue // whatsoever. This can happen as a result of monomorphizing a drop of a // generic. In order to make sure that generic and non-generic code behaves diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 9b78c31871fd7..eefb346d174b4 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -8,7 +8,7 @@ use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; use crate::mono::Visibility; -use crate::ty::{InstanceKind, TyCtxt}; +use crate::ty::{InstanceKind, ShimKind, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { pub fn codegen_instance_attrs( @@ -33,7 +33,7 @@ impl<'tcx> TyCtxt<'tcx> { // // A `ClosureOnceShim` with the track_caller attribute does not have a symbol, // and therefore can be skipped here. - if let InstanceKind::ReifyShim(_, _) = instance_kind + if let InstanceKind::Shim(ShimKind::ReifyShim(_, _)) = instance_kind && attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) { if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { @@ -54,8 +54,11 @@ impl<'tcx> TyCtxt<'tcx> { } // Ensure closure shims have the optimization properties of their closure applied to them. - if let InstanceKind::ClosureOnceShim { call_once: _, closure, track_caller: _ } = - instance_kind + if let InstanceKind::Shim(ShimKind::ClosureOnceShim { + call_once: _, + closure, + track_caller: _, + }) = instance_kind { let closure_attrs = self.codegen_fn_attrs(closure); attrs.to_mut().optimize = closure_attrs.optimize; diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index fb770076f0a26..5942f9dfa1def 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -75,7 +75,7 @@ impl<'tcx> ExportedSymbol<'tcx> { tcx.symbol_name(ty::Instance::resolve_async_drop_in_place_poll(tcx, def_id, ty)) } ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance { - def: ty::InstanceKind::ThreadLocalShim(def_id), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), args: ty::GenericArgs::empty(), }), ExportedSymbol::NoDefId(symbol_name) => symbol_name, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c12e72d1dce0f..23e6fc15c2ede 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -32,8 +32,8 @@ use crate::mir::interpret::{AllocRange, Scalar}; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::{ - self, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypeVisitableExt, - TypingEnv, UserTypeAnnotationIndex, + self, GenericArg, GenericArgsRef, Instance, InstanceKind, List, ShimKind, Ty, TyCtxt, + TypeVisitableExt, TypingEnv, UserTypeAnnotationIndex, }; mod basic_blocks; @@ -131,6 +131,10 @@ impl<'tcx> MirSource<'tcx> { MirSource { instance, promoted: None } } + pub fn from_shim(shim: ShimKind<'tcx>) -> Self { + MirSource { instance: InstanceKind::Shim(shim), promoted: None } + } + #[inline] pub fn def_id(&self) -> DefId { self.instance.def_id() diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 942c36f343343..1c7d261dd5978 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -218,7 +218,7 @@ impl<'a, 'tcx> MirDumper<'a, 'tcx> { // All drop shims have the same DefId, so we have to add the type // to get unique file names. let shim_disambiguator = match source.instance { - ty::InstanceKind::DropGlue(_, Some(ty)) => { + ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, Some(ty))) => { // Unfortunately, pretty-printed types are not very filename-friendly. // We do some filtering. let mut s = ".".to_owned(); @@ -229,7 +229,7 @@ impl<'a, 'tcx> MirDumper<'a, 'tcx> { })); s } - ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => { + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, ty)) => { let mut s = ".".to_owned(); s.extend(ty.to_string().chars().filter_map(|c| match c { ' ' => None, @@ -238,7 +238,7 @@ impl<'a, 'tcx> MirDumper<'a, 'tcx> { })); s } - ty::InstanceKind::AsyncDropGlue(_, ty) => { + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_, ty)) => { let ty::Coroutine(_, args) = ty.kind() else { bug!(); }; @@ -251,7 +251,7 @@ impl<'a, 'tcx> MirDumper<'a, 'tcx> { })); s } - ty::InstanceKind::FutureDropPollShim(_, proxy_cor, impl_cor) => { + ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_, proxy_cor, impl_cor)) => { let mut s = ".".to_owned(); s.extend(proxy_cor.to_string().chars().filter_map(|c| match c { ' ' => None, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index fb89e9ac884a0..35c47b761c5d4 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -347,27 +347,27 @@ macro_rules! make_mir_visitor { ty::InstanceKind::Item(_def_id) => {} ty::InstanceKind::Intrinsic(_def_id) - | ty::InstanceKind::VTableShim(_def_id) - | ty::InstanceKind::ReifyShim(_def_id, _) + | ty::InstanceKind::Shim(ty::ShimKind::VTableShim(_def_id)) + | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_def_id, _)) | ty::InstanceKind::Virtual(_def_id, _) - | ty::InstanceKind::ThreadLocalShim(_def_id) - | ty::InstanceKind::ClosureOnceShim { call_once: _def_id, closure: _, track_caller: _ } - | ty::InstanceKind::ConstructCoroutineInClosureShim { + | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(_def_id)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { call_once: _def_id, closure: _, track_caller: _ }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, receiver_by_ref: _, - } - | ty::InstanceKind::DropGlue(_def_id, None) => {} - - ty::InstanceKind::FnPtrShim(_def_id, ty) - | ty::InstanceKind::DropGlue(_def_id, Some(ty)) - | ty::InstanceKind::CloneShim(_def_id, ty) - | ty::InstanceKind::FnPtrAddrShim(_def_id, ty) - | ty::InstanceKind::AsyncDropGlue(_def_id, ty) - | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, ty) => { + }) + | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_def_id, None)) => {} + + ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(_def_id, ty)) + | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_def_id, Some(ty))) + | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(_def_id, ty)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(_def_id, ty)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_def_id, ty)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_def_id, ty)) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } - ty::InstanceKind::FutureDropPollShim(_def_id, proxy_ty, impl_ty) => { + ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_def_id, proxy_ty, impl_ty)) => { self.visit_ty($(& $mutability)? *proxy_ty, TyContext::Location(location)); self.visit_ty($(& $mutability)? *impl_ty, TyContext::Location(location)); } diff --git a/compiler/rustc_middle/src/mono.rs b/compiler/rustc_middle/src/mono.rs index 2c1a9d1ed7bfb..054b3e9a49680 100644 --- a/compiler/rustc_middle/src/mono.rs +++ b/compiler/rustc_middle/src/mono.rs @@ -22,7 +22,7 @@ use tracing::debug; use crate::dep_graph::dep_node::{make_compile_codegen_unit, make_compile_mono_item}; use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::ty::{self, GenericArgs, Instance, InstanceKind, SymbolName, Ty, TyCtxt}; +use crate::ty::{self, GenericArgs, Instance, InstanceKind, ShimKind, SymbolName, Ty, TyCtxt}; /// Describes how a monomorphization will be instantiated in object files. #[derive(PartialEq)] @@ -173,7 +173,7 @@ impl<'tcx> MonoItem<'tcx> { // incrementality (which wants small CGUs with as many things GloballyShared as possible). // The heuristics implemented here do better than a completely naive approach in the // compiler benchmark suite, but there is no reason to believe they are optimal. - if let InstanceKind::DropGlue(_, Some(ty)) = instance.def { + if let InstanceKind::Shim(ShimKind::DropGlue(_, Some(ty))) = instance.def { if tcx.sess.opts.optimize == OptLevel::No { return InstantiationMode::GloballyShared { may_conflict: false }; } @@ -523,20 +523,20 @@ impl<'tcx> CodegenUnit<'tcx> { match item { MonoItem::Fn(ref instance) => match instance.def { InstanceKind::Item(def) => def.as_local().map(|_| def), - InstanceKind::VTableShim(..) - | InstanceKind::ReifyShim(..) - | InstanceKind::Intrinsic(..) - | InstanceKind::FnPtrShim(..) + InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..) - | InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::DropGlue(..) - | InstanceKind::CloneShim(..) - | InstanceKind::ThreadLocalShim(..) - | InstanceKind::FnPtrAddrShim(..) - | InstanceKind::AsyncDropGlue(..) - | InstanceKind::FutureDropPollShim(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => None, + | InstanceKind::Shim(ShimKind::VTableShim(..)) + | InstanceKind::Shim(ShimKind::ReifyShim(..)) + | InstanceKind::Shim(ShimKind::FnPtrShim(..)) + | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) + | InstanceKind::Shim(ShimKind::DropGlue(..)) + | InstanceKind::Shim(ShimKind::CloneShim(..)) + | InstanceKind::Shim(ShimKind::ThreadLocalShim(..)) + | InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) + | InstanceKind::Shim(ShimKind::AsyncDropGlue(..)) + | InstanceKind::Shim(ShimKind::FutureDropPollShim(..)) + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(..)) => None, }, MonoItem::Static(def_id) => def_id.as_local().map(|_| def_id), MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.to_def_id()), diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index d4817888468fa..9370890c399ec 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1400,10 +1400,10 @@ rustc_queries! { } /// Generates a MIR body for the shim. - query mir_shims(key: ty::InstanceKind<'tcx>) -> &'tcx mir::Body<'tcx> { + query mir_shims(key: ty::ShimKind<'tcx>) -> &'tcx mir::Body<'tcx> { arena_cache desc { - "generating MIR shim for `{}`, instance={:?}", + "generating MIR shim for `{}`, kind={:?}", tcx.def_path_str(key.def_id()), key } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 346a26a685317..bbb92ee7e716b 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -63,6 +63,12 @@ impl QueryKey for () { } } +impl<'tcx> QueryKey for ty::ShimKind<'tcx> { + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.def_id()) + } +} + impl<'tcx> QueryKey for ty::InstanceKind<'tcx> { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 8734d2cde8152..2fc2a4a23c88c 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -75,6 +75,22 @@ pub enum InstanceKind<'tcx> { /// caller. Intrinsic(DefId), + /// Dynamic dispatch to `::fn`. + /// + /// This `InstanceKind` may have a callable MIR as the default implementation. + /// Calls to `Virtual` instances must be codegen'd as virtual calls through the vtable. + /// *This means we might not know exactly what is being called.* + /// + /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more + /// details on that). + Virtual(DefId, usize), + + Shim(ShimKind<'tcx>), +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(TyEncodable, TyDecodable, StableHash, TypeFoldable, TypeVisitable, Lift)] +pub enum ShimKind<'tcx> { /// `::method` where `method` receives unsizeable `self: Self` (part of the /// `unsized_fn_params` feature). /// @@ -106,16 +122,6 @@ pub enum InstanceKind<'tcx> { /// `DefId` is `FnTrait::call_*`. FnPtrShim(DefId, Ty<'tcx>), - /// Dynamic dispatch to `::fn`. - /// - /// This `InstanceKind` may have a callable MIR as the default implementation. - /// Calls to `Virtual` instances must be codegen'd as virtual calls through the vtable. - /// *This means we might not know exactly what is being called.* - /// - /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more - /// details on that). - Virtual(DefId, usize), - /// `<[FnMut/Fn closure] as FnOnce>::call_once`. /// /// The `DefId` is the ID of the `call_once` method in `FnOnce`. @@ -228,10 +234,12 @@ impl<'tcx> Instance<'tcx> { InstanceKind::Item(def) => tcx .upstream_monomorphizations_for(def) .and_then(|monos| monos.get(&self.args).cloned()), - InstanceKind::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.args), - InstanceKind::AsyncDropGlue(_, _) => None, - InstanceKind::FutureDropPollShim(_, _, _) => None, - InstanceKind::AsyncDropGlueCtorShim(_, _) => { + InstanceKind::Shim(ShimKind::DropGlue(_, Some(_))) => { + tcx.upstream_drop_glue_for(self.args) + } + InstanceKind::Shim(ShimKind::AsyncDropGlue(_, _)) => None, + InstanceKind::Shim(ShimKind::FutureDropPollShim(_, _, _)) => None, + InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(_, _)) => { tcx.upstream_async_drop_glue_for(self.args) } _ => None, @@ -244,45 +252,18 @@ impl<'tcx> InstanceKind<'tcx> { pub fn def_id(self) -> DefId { match self { InstanceKind::Item(def_id) - | InstanceKind::VTableShim(def_id) - | InstanceKind::ReifyShim(def_id, _) - | InstanceKind::FnPtrShim(def_id, _) | InstanceKind::Virtual(def_id, _) - | InstanceKind::Intrinsic(def_id) - | InstanceKind::ThreadLocalShim(def_id) - | InstanceKind::ClosureOnceShim { call_once: def_id, closure: _, track_caller: _ } - | ty::InstanceKind::ConstructCoroutineInClosureShim { - coroutine_closure_def_id: def_id, - receiver_by_ref: _, - } - | InstanceKind::DropGlue(def_id, _) - | InstanceKind::CloneShim(def_id, _) - | InstanceKind::FnPtrAddrShim(def_id, _) - | InstanceKind::FutureDropPollShim(def_id, _, _) - | InstanceKind::AsyncDropGlue(def_id, _) - | InstanceKind::AsyncDropGlueCtorShim(def_id, _) => def_id, + | InstanceKind::Intrinsic(def_id) => def_id, + InstanceKind::Shim(shim) => shim.def_id(), } } /// Returns the `DefId` of instances which might not require codegen locally. pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { match self { - ty::InstanceKind::Item(def) => Some(def), - ty::InstanceKind::DropGlue(def_id, Some(_)) - | InstanceKind::AsyncDropGlueCtorShim(def_id, _) - | InstanceKind::AsyncDropGlue(def_id, _) - | InstanceKind::FutureDropPollShim(def_id, ..) - | InstanceKind::ThreadLocalShim(def_id) => Some(def_id), - InstanceKind::VTableShim(..) - | InstanceKind::ReifyShim(..) - | InstanceKind::FnPtrShim(..) - | InstanceKind::Virtual(..) - | InstanceKind::Intrinsic(..) - | InstanceKind::ClosureOnceShim { .. } - | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::DropGlue(..) - | InstanceKind::CloneShim(..) - | InstanceKind::FnPtrAddrShim(..) => None, + InstanceKind::Item(def) => Some(def), + InstanceKind::Virtual(..) | InstanceKind::Intrinsic(..) => None, + InstanceKind::Shim(shim) => shim.def_id_if_not_guaranteed_local_codegen(), } } @@ -293,31 +274,28 @@ impl<'tcx> InstanceKind<'tcx> { /// `generates_cgu_internal_copy` for more information. pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool { use rustc_hir::definitions::DefPathData; - let def_id = match *self { - ty::InstanceKind::Item(def) => def, - ty::InstanceKind::DropGlue(_, Some(ty)) => return ty.is_array(), - ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => return ty.is_coroutine(), - ty::InstanceKind::FutureDropPollShim(_, _, _) => return false, - ty::InstanceKind::AsyncDropGlue(_, _) => return false, - ty::InstanceKind::ThreadLocalShim(_) => return false, - _ => return true, - }; - matches!( - tcx.def_key(def_id).disambiguated_data.data, - DefPathData::Ctor | DefPathData::Closure - ) + match *self { + InstanceKind::Item(def_id) => matches!( + tcx.def_key(def_id).disambiguated_data.data, + DefPathData::Ctor | DefPathData::Closure + ), + InstanceKind::Shim(shim) => shim.requires_inline(), + InstanceKind::Virtual(..) | InstanceKind::Intrinsic(..) => true, + } } pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { match *self { InstanceKind::Item(def_id) | InstanceKind::Virtual(def_id, _) - | InstanceKind::VTableShim(def_id) => { + | InstanceKind::Shim(ShimKind::VTableShim(def_id)) => { tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } - InstanceKind::ClosureOnceShim { call_once: _, closure: _, track_caller } => { - track_caller - } + InstanceKind::Shim(ShimKind::ClosureOnceShim { + call_once: _, + closure: _, + track_caller, + }) => track_caller, _ => false, } } @@ -330,22 +308,79 @@ impl<'tcx> InstanceKind<'tcx> { /// body should perform necessary instantiations. pub fn has_polymorphic_mir_body(&self) -> bool { match *self { - InstanceKind::CloneShim(..) - | InstanceKind::ThreadLocalShim(..) - | InstanceKind::FnPtrAddrShim(..) - | InstanceKind::FnPtrShim(..) - | InstanceKind::DropGlue(_, Some(_)) - | InstanceKind::FutureDropPollShim(..) - | InstanceKind::AsyncDropGlue(_, _) => false, - InstanceKind::AsyncDropGlueCtorShim(_, _) => false, - InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::DropGlue(..) - | InstanceKind::Item(_) - | InstanceKind::Intrinsic(..) - | InstanceKind::ReifyShim(..) - | InstanceKind::Virtual(..) - | InstanceKind::VTableShim(..) => true, + InstanceKind::Item(_) | InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..) => true, + InstanceKind::Shim(shim) => shim.has_polymorphic_mir_body(), + } + } +} + +impl<'tcx> ShimKind<'tcx> { + #[inline] + pub fn def_id(self) -> DefId { + match self { + ShimKind::VTableShim(def_id) + | ShimKind::ReifyShim(def_id, _) + | ShimKind::FnPtrShim(def_id, _) + | ShimKind::ThreadLocalShim(def_id) + | ShimKind::ClosureOnceShim { call_once: def_id, closure: _, track_caller: _ } + | ShimKind::ConstructCoroutineInClosureShim { + coroutine_closure_def_id: def_id, + receiver_by_ref: _, + } + | ShimKind::DropGlue(def_id, _) + | ShimKind::CloneShim(def_id, _) + | ShimKind::FnPtrAddrShim(def_id, _) + | ShimKind::FutureDropPollShim(def_id, _, _) + | ShimKind::AsyncDropGlue(def_id, _) + | ShimKind::AsyncDropGlueCtorShim(def_id, _) => def_id, + } + } + + /// Returns the `DefId` of instances which might not require codegen locally. + pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { + match self { + ShimKind::DropGlue(def_id, Some(_)) + | ShimKind::AsyncDropGlueCtorShim(def_id, _) + | ShimKind::AsyncDropGlue(def_id, _) + | ShimKind::FutureDropPollShim(def_id, ..) + | ShimKind::ThreadLocalShim(def_id) => Some(def_id), + ShimKind::VTableShim(..) + | ShimKind::ReifyShim(..) + | ShimKind::FnPtrShim(..) + | ShimKind::ClosureOnceShim { .. } + | ShimKind::ConstructCoroutineInClosureShim { .. } + | ShimKind::DropGlue(..) + | ShimKind::CloneShim(..) + | ShimKind::FnPtrAddrShim(..) => None, + } + } + + pub fn requires_inline(&self) -> bool { + match self { + ShimKind::DropGlue(_, Some(ty)) => ty.is_array(), + ShimKind::AsyncDropGlueCtorShim(_, ty) => ty.is_coroutine(), + ShimKind::FutureDropPollShim(_, _, _) => false, + ShimKind::AsyncDropGlue(_, _) => false, + ShimKind::ThreadLocalShim(_) => false, + _ => true, + } + } + + pub fn has_polymorphic_mir_body(&self) -> bool { + match *self { + ShimKind::CloneShim(..) + | ShimKind::ThreadLocalShim(..) + | ShimKind::FnPtrAddrShim(..) + | ShimKind::FnPtrShim(..) + | ShimKind::DropGlue(_, Some(_)) + | ShimKind::FutureDropPollShim(..) + | ShimKind::AsyncDropGlue(_, _) => false, + ShimKind::AsyncDropGlueCtorShim(_, _) => false, + ShimKind::ClosureOnceShim { .. } + | ShimKind::ConstructCoroutineInClosureShim { .. } + | ShimKind::DropGlue(..) + | ShimKind::ReifyShim(..) + | ShimKind::VTableShim(..) => true, } } } @@ -416,7 +451,11 @@ fn resolve_async_drop_poll<'tcx>(mut cor_ty: Ty<'tcx>) -> Instance<'tcx> { continue; } else { return Instance { - def: ty::InstanceKind::FutureDropPollShim(poll_def_id, first_cor, cor_ty), + def: ty::InstanceKind::Shim(ShimKind::FutureDropPollShim( + poll_def_id, + first_cor, + cor_ty, + )), args: proxy_args, }; } @@ -426,12 +465,16 @@ fn resolve_async_drop_poll<'tcx>(mut cor_ty: Ty<'tcx>) -> Instance<'tcx> { }; if first_cor != cor_ty { return Instance { - def: ty::InstanceKind::FutureDropPollShim(poll_def_id, first_cor, cor_ty), + def: ty::InstanceKind::Shim(ShimKind::FutureDropPollShim( + poll_def_id, + first_cor, + cor_ty, + )), args: proxy_args, }; } else { return Instance { - def: ty::InstanceKind::AsyncDropGlue(poll_def_id, cor_ty), + def: ty::InstanceKind::Shim(ShimKind::AsyncDropGlue(poll_def_id, cor_ty)), args: child_args, }; } @@ -599,11 +642,11 @@ impl<'tcx> Instance<'tcx> { match resolved.def { InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceKind::ReifyShim(def, reason); + resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def, reason)); } InstanceKind::Virtual(def_id, _) => { debug!(" => fn pointer created for virtual call"); - resolved.def = InstanceKind::ReifyShim(def_id, reason); + resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)); } _ if tcx.sess.is_sanitizer_kcfi_enabled() => { // Reify `::call`-like method implementations @@ -611,7 +654,10 @@ impl<'tcx> Instance<'tcx> { // Reroute through a reify via the *unresolved* instance. The resolved one can't // be directly reified because it's closure-like. The reify can handle the // unresolved instance. - resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args } + resolved = Instance { + def: InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)), + args, + } // Reify `Trait::method` implementations if the trait is dyn-compatible. } else if let Some(assoc) = tcx.opt_associated_item(def_id) && let AssocContainer::Trait | AssocContainer::TraitImpl(Ok(_)) = @@ -620,7 +666,8 @@ impl<'tcx> Instance<'tcx> { { // If this function could also go in a vtable, we need to `ReifyShim` it with // KCFI because it can only attach one type per function. - resolved.def = InstanceKind::ReifyShim(resolved.def_id(), reason) + resolved.def = + InstanceKind::Shim(ShimKind::ReifyShim(resolved.def_id(), reason)) } } _ => {} @@ -645,7 +692,7 @@ impl<'tcx> Instance<'tcx> { if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - return Instance { def: InstanceKind::VTableShim(def_id), args }; + return Instance { def: InstanceKind::Shim(ShimKind::VTableShim(def_id)), args }; } let mut resolved = Instance::expect_resolve(tcx, typing_env, def_id, args, span); @@ -688,19 +735,22 @@ impl<'tcx> Instance<'tcx> { // Create a shim for the `FnOnce/FnMut/Fn` method we are calling // - unlike functions, invoking a closure always goes through a // trait. - resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }; + resolved = Instance { + def: InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)), + args, + }; } else { debug!( " => vtable fn pointer created for function with #[track_caller]: {:?}", def ); - resolved.def = InstanceKind::ReifyShim(def, reason); + resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def, reason)); } } } InstanceKind::Virtual(def_id, _) => { debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceKind::ReifyShim(def_id, reason) + resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)) } _ => {} } @@ -770,8 +820,11 @@ impl<'tcx> Instance<'tcx> { .def_id; let track_caller = tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); - let def = - ty::InstanceKind::ClosureOnceShim { call_once, closure: closure_did, track_caller }; + let def = ty::InstanceKind::Shim(ShimKind::ClosureOnceShim { + call_once, + closure: closure_did, + track_caller, + }); let self_ty = Ty::new_closure(tcx, closure_did, args); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 10a5f380d4c80..8e51007edfdfe 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -85,7 +85,7 @@ pub use self::context::{ CtxtInterners, CurrentGcx, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls, }; pub use self::fold::*; -pub use self::instance::{Instance, InstanceKind, ReifyReason}; +pub use self::instance::{Instance, InstanceKind, ReifyReason, ShimKind}; pub(crate) use self::list::RawList; pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::opaque_types::OpaqueTypeKey; @@ -1802,20 +1802,9 @@ impl<'tcx> TyCtxt<'tcx> { _ => self.optimized_mir(def), } } - ty::InstanceKind::VTableShim(..) - | ty::InstanceKind::ReifyShim(..) - | ty::InstanceKind::Intrinsic(..) - | ty::InstanceKind::FnPtrShim(..) - | ty::InstanceKind::Virtual(..) - | ty::InstanceKind::ClosureOnceShim { .. } - | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::FutureDropPollShim(..) - | ty::InstanceKind::DropGlue(..) - | ty::InstanceKind::CloneShim(..) - | ty::InstanceKind::ThreadLocalShim(..) - | ty::InstanceKind::FnPtrAddrShim(..) - | ty::InstanceKind::AsyncDropGlueCtorShim(..) - | ty::InstanceKind::AsyncDropGlue(..) => self.mir_shims(instance), + ty::InstanceKind::Intrinsic(..) => bug!("intrinsics have no instance MIR"), + ty::InstanceKind::Virtual(..) => bug!("virtual dispatches have no instance MIR"), + ty::InstanceKind::Shim(shim) => self.mir_shims(shim), }; assert!( @@ -1941,7 +1930,7 @@ impl<'tcx> TyCtxt<'tcx> { if args[0].has_placeholders() || args[0].has_non_region_param() { return Err(self.layout_error(LayoutError::TooGeneric(ty()))); } - let instance = InstanceKind::AsyncDropGlue(def_id, Ty::new_coroutine(self, def_id, args)); + let instance = ShimKind::AsyncDropGlue(def_id, Ty::new_coroutine(self, def_id, args)); self.mir_shims(instance) .coroutine_layout_raw() .ok_or_else(|| self.layout_error(LayoutError::Unknown(ty()))) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 29875a3530c15..0552bf1dd1636 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -367,35 +367,44 @@ impl<'tcx, P: Printer<'tcx> + std::fmt::Write> Print

for ty::Instance<'tcx> { cx.print_def_path(self.def_id(), self.args)?; match self.def { ty::InstanceKind::Item(_) => {} - ty::InstanceKind::VTableShim(_) => cx.write_str(" - shim(vtable)")?, - ty::InstanceKind::ReifyShim(_, None) => cx.write_str(" - shim(reify)")?, - ty::InstanceKind::ReifyShim(_, Some(ty::ReifyReason::FnPtr)) => { - cx.write_str(" - shim(reify-fnptr)")? - } - ty::InstanceKind::ReifyShim(_, Some(ty::ReifyReason::Vtable)) => { - cx.write_str(" - shim(reify-vtable)")? - } - ty::InstanceKind::ThreadLocalShim(_) => cx.write_str(" - shim(tls)")?, ty::InstanceKind::Intrinsic(_) => cx.write_str(" - intrinsic")?, ty::InstanceKind::Virtual(_, num) => cx.write_str(&format!(" - virtual#{num}"))?, - ty::InstanceKind::FnPtrShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, - ty::InstanceKind::ClosureOnceShim { .. } => cx.write_str(" - shim")?, - ty::InstanceKind::ConstructCoroutineInClosureShim { .. } => cx.write_str(" - shim")?, - ty::InstanceKind::DropGlue(_, None) => cx.write_str(" - shim(None)")?, - ty::InstanceKind::DropGlue(_, Some(ty)) => { - cx.write_str(&format!(" - shim(Some({ty}))"))? + ty::InstanceKind::Shim(shim) => { + cx.write_str(" - ")?; + shim.print(cx)?; } - ty::InstanceKind::CloneShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, - ty::InstanceKind::FnPtrAddrShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, - ty::InstanceKind::FutureDropPollShim(_, proxy_ty, impl_ty) => { - cx.write_str(&format!(" - dropshim({proxy_ty}-{impl_ty})"))? + } + Ok(()) + } +} + +impl<'tcx, P: Printer<'tcx> + std::fmt::Write> Print

for ty::ShimKind<'tcx> { + fn print(&self, cx: &mut P) -> Result<(), PrintError> { + match self { + ty::ShimKind::VTableShim(_) => cx.write_str("shim(vtable)"), + ty::ShimKind::ReifyShim(_, None) => cx.write_str("shim(reify)"), + ty::ShimKind::ReifyShim(_, Some(ty::ReifyReason::FnPtr)) => { + cx.write_str("shim(reify-fnptr)") } - ty::InstanceKind::AsyncDropGlue(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, - ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => { - cx.write_str(&format!(" - shim(Some({ty}))"))? + ty::ShimKind::ReifyShim(_, Some(ty::ReifyReason::Vtable)) => { + cx.write_str("shim(reify-vtable)") } - }; - Ok(()) + ty::ShimKind::ThreadLocalShim(_) => cx.write_str("shim(tls)"), + ty::ShimKind::FnPtrShim(_, ty) => cx.write_str(&format!("shim({ty})")), + ty::ShimKind::ClosureOnceShim { .. } => cx.write_str("shim"), + ty::ShimKind::ConstructCoroutineInClosureShim { .. } => cx.write_str("shim"), + ty::ShimKind::DropGlue(_, None) => cx.write_str("shim(None)"), + ty::ShimKind::DropGlue(_, Some(ty)) => cx.write_str(&format!("shim(Some({ty}))")), + ty::ShimKind::CloneShim(_, ty) => cx.write_str(&format!("shim({ty})")), + ty::ShimKind::FnPtrAddrShim(_, ty) => cx.write_str(&format!("shim({ty})")), + ty::ShimKind::FutureDropPollShim(_, proxy_ty, impl_ty) => { + cx.write_str(&format!("dropshim({proxy_ty}-{impl_ty})")) + } + ty::ShimKind::AsyncDropGlue(_, ty) => cx.write_str(&format!("shim({ty})")), + ty::ShimKind::AsyncDropGlueCtorShim(_, ty) => { + cx.write_str(&format!("shim(Some({ty}))")) + } + } } } diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 5be6887e937a1..41b973476af94 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -206,7 +206,7 @@ pub(super) fn create_coroutine_drop_shim<'tcx>( // Update the body's def to become the drop glue. let coroutine_instance = body.source.instance; let drop_glue = tcx.require_lang_item(LangItem::DropGlue, body.span); - let drop_instance = InstanceKind::DropGlue(drop_glue, Some(coroutine_ty)); + let drop_instance = InstanceKind::Shim(ShimKind::DropGlue(drop_glue, Some(coroutine_ty))); // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible // filename. diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs index bb57ca1cd90a7..53283680c0966 100644 --- a/compiler/rustc_mir_transform/src/coroutine/mod.rs +++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs @@ -71,7 +71,7 @@ use rustc_index::{Idx, IndexVec, indexvec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{ - self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, + self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, ShimKind, Ty, TyCtxt, }; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::impls::always_storage_live_locals; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index df71cd48a77fe..a1575a21e9073 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -15,7 +15,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::{ - self, Instance, InstanceKind, Ty, TyCtxt, TypeFlags, TypeVisitableExt, Unnormalized, + self, Instance, InstanceKind, ShimKind, Ty, TyCtxt, TypeFlags, TypeVisitableExt, Unnormalized, }; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::Spanned; @@ -739,18 +739,21 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( // the correct param-env for types being dropped. Stall resolving // the MIR for this instance until all of its const params are // substituted. - InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => { + InstanceKind::Shim(ShimKind::DropGlue(_, Some(ty))) + if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => + { debug!("still needs substitution"); return Err("implementation limitation -- HACK for dropping polymorphic type"); } - InstanceKind::AsyncDropGlue(_, ty) | InstanceKind::AsyncDropGlueCtorShim(_, ty) => { + InstanceKind::Shim(ShimKind::AsyncDropGlue(_, ty)) + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(_, ty)) => { return if ty.still_further_specializable() { Err("still needs substitution") } else { Ok(()) }; } - InstanceKind::FutureDropPollShim(_, ty, ty2) => { + InstanceKind::Shim(ShimKind::FutureDropPollShim(_, ty, ty2)) => { return if ty.still_further_specializable() || ty2.still_further_specializable() { Err("still needs substitution") } else { @@ -762,15 +765,15 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. - InstanceKind::VTableShim(_) - | InstanceKind::ReifyShim(..) - | InstanceKind::FnPtrShim(..) - | InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::DropGlue(..) - | InstanceKind::CloneShim(..) - | InstanceKind::ThreadLocalShim(..) - | InstanceKind::FnPtrAddrShim(..) => return Ok(()), + InstanceKind::Shim(ShimKind::VTableShim(_)) + | InstanceKind::Shim(ShimKind::ReifyShim(..)) + | InstanceKind::Shim(ShimKind::FnPtrShim(..)) + | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) + | InstanceKind::Shim(ShimKind::DropGlue(..)) + | InstanceKind::Shim(ShimKind::CloneShim(..)) + | InstanceKind::Shim(ShimKind::ThreadLocalShim(..)) + | InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) => return Ok(()), } if inliner.tcx().is_constructor(callee_def_id) { @@ -1370,8 +1373,8 @@ fn try_instance_mir<'tcx>( tcx: TyCtxt<'tcx>, instance: InstanceKind<'tcx>, ) -> Result<&'tcx Body<'tcx>, &'static str> { - if let ty::InstanceKind::DropGlue(_, Some(ty)) | ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) = - instance + if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, Some(ty))) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, ty)) = instance && let ty::Adt(def, args) = ty.kind() { let fields = def.all_fields(); diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 9d031b6548021..0fd1a5f240758 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -4,7 +4,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::limit::Limit; use rustc_middle::mir::TerminatorKind; -use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, ShimKind, TyCtxt, TypeVisitableExt}; use rustc_span::sym; use tracing::{instrument, trace}; @@ -26,24 +26,24 @@ fn should_recurse<'tcx>(tcx: TyCtxt<'tcx>, callee: ty::Instance<'tcx>) -> bool { // These have MIR and if that MIR is inlined, instantiated and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way - InstanceKind::VTableShim(_) - | InstanceKind::ReifyShim(..) - | InstanceKind::FnPtrShim(..) - | InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::ThreadLocalShim { .. } - | InstanceKind::CloneShim(..) => {} + InstanceKind::Shim(ShimKind::VTableShim(_)) + | InstanceKind::Shim(ShimKind::ReifyShim(..)) + | InstanceKind::Shim(ShimKind::FnPtrShim(..)) + | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) + | InstanceKind::Shim(ShimKind::ThreadLocalShim { .. }) + | InstanceKind::Shim(ShimKind::CloneShim(..)) => {} // This shim does not call any other functions, thus there can be no recursion. - InstanceKind::FnPtrAddrShim(..) => return false, + InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) => return false, // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. - InstanceKind::DropGlue(..) - | InstanceKind::FutureDropPollShim(..) - | InstanceKind::AsyncDropGlue(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => { + InstanceKind::Shim(ShimKind::DropGlue(..)) + | InstanceKind::Shim(ShimKind::FutureDropPollShim(..)) + | InstanceKind::Shim(ShimKind::AsyncDropGlue(..)) + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(..)) => { if callee.has_param() { return false; } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 6d9b8feea05f4..d6061edb74ce3 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -31,16 +31,15 @@ pub(super) fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } -fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<'tcx> { - debug!("make_shim({:?})", instance); +fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Body<'tcx> { + debug!("make_shim({:?})", shim); - let mut result = match instance { - ty::InstanceKind::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceKind::VTableShim(def_id) => { + let mut result = match shim { + ty::ShimKind::VTableShim(def_id) => { let adjustment = Adjustment::Deref { source: DerefSource::MutPtr }; - build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id)) + build_call_shim(tcx, shim, Some(adjustment), CallKind::Direct(def_id)) } - ty::InstanceKind::FnPtrShim(def_id, ty) => { + ty::ShimKind::FnPtrShim(def_id, ty) => { let trait_ = tcx.parent(def_id); // Supports `Fn` or `async Fn` traits. let adjustment = match tcx @@ -53,17 +52,17 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< None => bug!("fn pointer {:?} is not an fn", ty), }; - build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty)) + build_call_shim(tcx, shim, Some(adjustment), CallKind::Indirect(ty)) } // We are generating a call back to our def-id, which the // codegen backend knows to turn to an actual call, be it // a virtual call, or a direct call to a function for which // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). - ty::InstanceKind::ReifyShim(def_id, _) => { - build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) + ty::ShimKind::ReifyShim(def_id, _) => { + build_call_shim(tcx, shim, None, CallKind::Direct(def_id)) } - ty::InstanceKind::ClosureOnceShim { call_once: _, closure: _, track_caller: _ } => { + ty::ShimKind::ClosureOnceShim { call_once: _, closure: _, track_caller: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP); let call_mut = tcx .associated_items(fn_mut) @@ -72,15 +71,15 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< .unwrap() .def_id; - build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) + build_call_shim(tcx, shim, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } - ty::InstanceKind::ConstructCoroutineInClosureShim { + ty::ShimKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref, } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), - ty::InstanceKind::DropGlue(def_id, ty) => { + ty::ShimKind::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? if let Some(&ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) { @@ -110,7 +109,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args).skip_norm_wip(); - debug!("make_shim({:?}) = {:?}", instance, body); + debug!("make_shim({:?}) = {:?}", shim, body); pm::run_passes( tcx, @@ -129,10 +128,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< build_drop_shim(tcx, def_id, ty, ty::TypingEnv::post_analysis(tcx, def_id)) } - ty::InstanceKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance), - ty::InstanceKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), - ty::InstanceKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), - ty::InstanceKind::FutureDropPollShim(def_id, proxy_ty, impl_ty) => { + ty::ShimKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, shim), + ty::ShimKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), + ty::ShimKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), + ty::ShimKind::FutureDropPollShim(def_id, proxy_ty, impl_ty) => { let mut body = async_destructor_ctor::build_future_drop_poll_shim(tcx, def_id, proxy_ty, impl_ty); @@ -148,10 +147,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< pm::Optimizations::Allowed, ); run_optimization_passes(tcx, &mut body); - debug!("make_shim({:?}) = {:?}", instance, body); + debug!("make_shim({:?}) = {:?}", shim, body); return body; } - ty::InstanceKind::AsyncDropGlue(def_id, ty) => { + ty::ShimKind::AsyncDropGlue(def_id, ty) => { let mut body = async_destructor_ctor::build_async_drop_shim(tcx, def_id, ty); // Main pass required here is StateTransform to convert sync drop ladder @@ -170,23 +169,17 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< Some(MirPhase::Runtime(RuntimePhase::PostCleanup)), ); run_optimization_passes(tcx, &mut body); - debug!("make_shim({:?}) = {:?}", instance, body); + debug!("make_shim({:?}) = {:?}", shim, body); return body; } - ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) => { + ty::ShimKind::AsyncDropGlueCtorShim(def_id, ty) => { let body = async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty); - debug!("make_shim({:?}) = {:?}", instance, body); + debug!("make_shim({:?}) = {:?}", shim, body); return body; } - ty::InstanceKind::Virtual(..) => { - bug!("InstanceKind::Virtual ({:?}) is for direct calls only", instance) - } - ty::InstanceKind::Intrinsic(_) => { - bug!("creating shims from intrinsics ({:?}) is unsupported", instance) - } }; - debug!("make_shim({:?}) = untransformed {:?}", instance, result); + debug!("make_shim({:?}) = untransformed {:?}", shim, result); deref_finder(tcx, &mut result, false); @@ -211,7 +204,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< Some(MirPhase::Runtime(RuntimePhase::Optimized)), ); - debug!("make_shim({:?}) = {:?}", instance, result); + debug!("make_shim({:?}) = {:?}", shim, result); result } @@ -300,7 +293,7 @@ pub fn build_drop_shim<'tcx>( } block(&mut blocks, TerminatorKind::Return); - let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty)); + let source = MirSource::from_shim(ty::ShimKind::DropGlue(def_id, ty)); let mut body = new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); @@ -480,11 +473,8 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { } } -fn build_thread_local_shim<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::InstanceKind<'tcx>, -) -> Body<'tcx> { - let def_id = instance.def_id(); +fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Body<'tcx> { + let def_id = shim.def_id(); let span = tcx.def_span(def_id); let source_info = SourceInfo::outermost(span); @@ -502,7 +492,7 @@ fn build_thread_local_shim<'tcx>( )]); new_body( - MirSource::from_instance(instance), + MirSource::from_shim(shim), blocks, IndexVec::from_raw(vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]), 0, @@ -565,7 +555,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { } fn into_mir(self) -> Body<'tcx> { - let source = MirSource::from_instance(ty::InstanceKind::CloneShim( + let source = MirSource::from_shim(ty::ShimKind::CloneShim( self.def_id, self.sig.inputs_and_output[0], )); @@ -776,14 +766,14 @@ impl<'tcx> CloneShimBuilder<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] fn build_call_shim<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceKind<'tcx>, + shim: ty::ShimKind<'tcx>, rcvr_adjustment: Option, call_kind: CallKind<'tcx>, ) -> Body<'tcx> { // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used // to instantiate into the signature of the shim. It is not necessary for users of this // MIR body to perform further instantiations (see `InstanceKind::has_polymorphic_mir_body`). - let (sig_args, untuple_args) = if let ty::InstanceKind::FnPtrShim(_, ty) = instance { + let (sig_args, untuple_args) = if let ty::ShimKind::FnPtrShim(_, ty) = shim { let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx)); let untuple_args = sig.inputs(); @@ -796,12 +786,12 @@ fn build_call_shim<'tcx>( (None, None) }; - let def_id = instance.def_id(); + let def_id = shim.def_id(); let sig = tcx.fn_sig(def_id); let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig)); - assert_eq!(sig_args.is_some(), !instance.has_polymorphic_mir_body()); + assert_eq!(sig_args.is_some(), !shim.has_polymorphic_mir_body()); let mut sig = if let Some(sig_args) = sig_args { sig.instantiate(tcx, &sig_args).skip_norm_wip() } else { @@ -830,14 +820,14 @@ fn build_call_shim<'tcx>( DerefSource::MutRef => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fnty), DerefSource::MutPtr => Ty::new_mut_ptr(tcx, fnty), }, - Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {instance:?}"), + Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {shim:?}"), }; sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); } // FIXME: Avoid having to adjust the signature both here and in // `fn_sig_for_fn_abi`. - if let ty::InstanceKind::VTableShim(..) = instance { + if let ty::ShimKind::VTableShim(..) = shim { // Modify fn(self, ...) to fn(self: *mut Self, ...) let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; @@ -995,7 +985,7 @@ fn build_call_shim<'tcx>( } let mut body = - new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span); + new_body(MirSource::from_shim(shim), blocks, local_decls, sig.inputs().len(), span); if let ExternAbi::RustCall = sig.abi() { body.spread_arg = Some(Local::new(sig.inputs().len())); @@ -1119,7 +1109,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }), false, ); - let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty)); + let source = MirSource::from_shim(ty::ShimKind::FnPtrAddrShim(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } @@ -1218,7 +1208,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>( false, ); - let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim { + let source = MirSource::from_shim(ty::ShimKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref, }); diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index da88247800372..b23ab7842d51f 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -106,7 +106,7 @@ pub(super) fn build_async_drop_shim<'tcx>( ); block(&mut blocks, TerminatorKind::Return); - let source = MirSource::from_instance(ty::InstanceKind::AsyncDropGlue(def_id, ty)); + let source = MirSource::from_shim(ty::ShimKind::AsyncDropGlue(def_id, ty)); let mut body = new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); @@ -175,17 +175,17 @@ pub(super) fn build_future_drop_poll_shim<'tcx>( proxy_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, ) -> Body<'tcx> { - let instance = ty::InstanceKind::FutureDropPollShim(def_id, proxy_ty, impl_ty); + let shim = ty::ShimKind::FutureDropPollShim(def_id, proxy_ty, impl_ty); let ty::Coroutine(coroutine_def_id, _) = impl_ty.kind() else { - bug!("build_future_drop_poll_shim not for coroutine impl type: ({:?})", instance); + bug!("build_future_drop_poll_shim not for coroutine impl type: ({:?})", shim); }; let span = tcx.def_span(def_id); if tcx.is_async_drop_in_place_coroutine(*coroutine_def_id) { - build_adrop_for_adrop_shim(tcx, proxy_ty, impl_ty, span, instance) + build_adrop_for_adrop_shim(tcx, proxy_ty, impl_ty, span, shim) } else { - build_adrop_for_coroutine_shim(tcx, proxy_ty, impl_ty, span, instance) + build_adrop_for_coroutine_shim(tcx, proxy_ty, impl_ty, span, shim) } } @@ -198,16 +198,16 @@ fn build_adrop_for_coroutine_shim<'tcx>( proxy_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, span: Span, - instance: ty::InstanceKind<'tcx>, + shim: ty::ShimKind<'tcx>, ) -> Body<'tcx> { let ty::Coroutine(coroutine_def_id, impl_args) = impl_ty.kind() else { - bug!("build_adrop_for_coroutine_shim not for coroutine impl type: ({:?})", instance); + bug!("build_adrop_for_coroutine_shim not for coroutine impl type: ({:?})", shim); }; let source_info = SourceInfo::outermost(span); let body = tcx.optimized_mir(*coroutine_def_id).future_drop_poll().unwrap(); let mut body: Body<'tcx> = EarlyBinder::bind(body.clone()).instantiate(tcx, impl_args).skip_norm_wip(); - body.source.instance = instance; + body.source.instance = ty::InstanceKind::Shim(shim); body.phase = MirPhase::Runtime(RuntimePhase::Initial); body.var_debug_info.clear(); @@ -291,7 +291,7 @@ fn build_adrop_for_adrop_shim<'tcx>( proxy_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, span: Span, - instance: ty::InstanceKind<'tcx>, + shim: ty::ShimKind<'tcx>, ) -> Body<'tcx> { let source_info = SourceInfo::outermost(span); let proxy_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, proxy_ty); @@ -413,7 +413,7 @@ fn build_adrop_for_adrop_shim<'tcx>( false, )); - let source = MirSource::from_instance(instance); + let source = MirSource::from_shim(shim); let mut body = new_body(source, blocks, locals, sig.inputs().len(), span); body.phase = MirPhase::Runtime(RuntimePhase::Initial); return body; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 0421edc543151..7c4fce02ff005 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -226,8 +226,8 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, - TypeVisitable, TypeVisitableExt, TypeVisitor, Unnormalized, VtblEntry, + self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, ShimKind, Ty, TyCtxt, + TypeFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, Unnormalized, VtblEntry, }; use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; @@ -447,7 +447,7 @@ fn collect_items_rec<'tcx>( used_items.push(respan( starting_item.span, MonoItem::Fn(Instance { - def: InstanceKind::ThreadLocalShim(def_id), + def: InstanceKind::Shim(ShimKind::ThreadLocalShim(def_id)), args: GenericArgs::empty(), }), )); @@ -1013,10 +1013,10 @@ fn visit_instance_use<'tcx>( bug!("{:?} being reified", instance); } } - ty::InstanceKind::ThreadLocalShim(..) => { + ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) => { bug!("{:?} being reified", instance); } - ty::InstanceKind::DropGlue(_, None) => { + ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None)) => { // Don't need to emit noop drop glue if we are calling directly. // // Note that we also optimize away the call to visit_instance_use in vtable construction @@ -1025,18 +1025,18 @@ fn visit_instance_use<'tcx>( output.push(create_fn_mono_item(tcx, instance, source)); } } - ty::InstanceKind::DropGlue(_, Some(_)) - | ty::InstanceKind::FutureDropPollShim(..) - | ty::InstanceKind::AsyncDropGlue(_, _) - | ty::InstanceKind::AsyncDropGlueCtorShim(_, _) - | ty::InstanceKind::VTableShim(..) - | ty::InstanceKind::ReifyShim(..) - | ty::InstanceKind::ClosureOnceShim { .. } - | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::Item(..) - | ty::InstanceKind::FnPtrShim(..) - | ty::InstanceKind::CloneShim(..) - | ty::InstanceKind::FnPtrAddrShim(..) => { + ty::InstanceKind::Item(..) + | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, Some(_))) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_, _)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, _)) + | ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(..)) => { output.push(create_fn_mono_item(tcx, instance, source)); } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index aee7153419883..79b47c8e5944d 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -115,7 +115,7 @@ use rustc_middle::mono::{ MonoItemPartitions, Visibility, }; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; -use rustc_middle::ty::{self, InstanceKind, TyCtxt}; +use rustc_middle::ty::{self, InstanceKind, ShimKind, TyCtxt}; use rustc_middle::util::Providers; use rustc_session::CodegenUnits; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; @@ -630,20 +630,22 @@ fn characteristic_def_id_of_mono_item<'tcx>( MonoItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceKind::Item(def) => def, - ty::InstanceKind::VTableShim(..) - | ty::InstanceKind::ReifyShim(..) - | ty::InstanceKind::FnPtrShim(..) - | ty::InstanceKind::ClosureOnceShim { .. } - | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::Intrinsic(..) - | ty::InstanceKind::DropGlue(..) + ty::InstanceKind::Intrinsic(..) | ty::InstanceKind::Virtual(..) - | ty::InstanceKind::CloneShim(..) - | ty::InstanceKind::ThreadLocalShim(..) - | ty::InstanceKind::FnPtrAddrShim(..) - | ty::InstanceKind::FutureDropPollShim(..) - | ty::InstanceKind::AsyncDropGlue(..) - | ty::InstanceKind::AsyncDropGlueCtorShim(..) => return None, + | ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + .. + }) + | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(..)) + | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(..)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(..)) => return None, }; // If this is a method, we want to put it into the same module as @@ -794,27 +796,27 @@ fn mono_item_visibility<'tcx>( let def_id = match instance.def { InstanceKind::Item(def_id) - | InstanceKind::DropGlue(def_id, Some(_)) - | InstanceKind::FutureDropPollShim(def_id, _, _) - | InstanceKind::AsyncDropGlue(def_id, _) - | InstanceKind::AsyncDropGlueCtorShim(def_id, _) => def_id, + | InstanceKind::Shim(ShimKind::DropGlue(def_id, Some(_))) + | InstanceKind::Shim(ShimKind::FutureDropPollShim(def_id, _, _)) + | InstanceKind::Shim(ShimKind::AsyncDropGlue(def_id, _)) + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(def_id, _)) => def_id, // We match the visibility of statics here - InstanceKind::ThreadLocalShim(def_id) => { + InstanceKind::Shim(ShimKind::ThreadLocalShim(def_id)) => { return static_visibility(tcx, can_be_internalized, def_id); } // These are all compiler glue and such, never exported, always hidden. - InstanceKind::VTableShim(..) - | InstanceKind::ReifyShim(..) - | InstanceKind::FnPtrShim(..) + InstanceKind::Shim(ShimKind::VTableShim(..)) + | InstanceKind::Shim(ShimKind::ReifyShim(..)) + | InstanceKind::Shim(ShimKind::FnPtrShim(..)) | InstanceKind::Virtual(..) | InstanceKind::Intrinsic(..) - | InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::DropGlue(..) - | InstanceKind::CloneShim(..) - | InstanceKind::FnPtrAddrShim(..) => return Visibility::Hidden, + | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) + | InstanceKind::Shim(ShimKind::DropGlue(..)) + | InstanceKind::Shim(ShimKind::CloneShim(..)) + | InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) => return Visibility::Hidden, }; // Both the `start_fn` lang item and `main` itself should not be exported, @@ -1331,8 +1333,8 @@ pub(crate) fn provide(providers: &mut Providers) { // "Normal" functions size estimate: the number of // statements, plus one for the terminator. InstanceKind::Item(..) - | InstanceKind::DropGlue(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => { + | InstanceKind::Shim(ShimKind::DropGlue(..)) + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(..)) => { let mir = tcx.instance_mir(instance.def); mir.basic_blocks .iter() diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 4218c21f508d3..5807d79c8e03c 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -990,18 +990,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { ty::InstanceKind::Virtual(_def_id, idx) => { crate::mir::mono::InstanceKind::Virtual { idx } } - ty::InstanceKind::VTableShim(..) - | ty::InstanceKind::ReifyShim(..) - | ty::InstanceKind::FnPtrAddrShim(..) - | ty::InstanceKind::ClosureOnceShim { .. } - | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::ThreadLocalShim(..) - | ty::InstanceKind::DropGlue(..) - | ty::InstanceKind::CloneShim(..) - | ty::InstanceKind::FnPtrShim(..) - | ty::InstanceKind::FutureDropPollShim(..) - | ty::InstanceKind::AsyncDropGlue(..) - | ty::InstanceKind::AsyncDropGlueCtorShim(..) => crate::mir::mono::InstanceKind::Shim, + ty::InstanceKind::Shim(..) => crate::mir::mono::InstanceKind::Shim, }; crate::mir::mono::Instance { def, kind } } diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index c309df59e9eca..87a8661edeb65 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -645,7 +645,7 @@ impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> { /// Check if this is an empty DropGlue shim. pub fn is_empty_drop_shim(&self, instance: ty::Instance<'tcx>) -> bool { - matches!(instance.def, ty::InstanceKind::DropGlue(_, None)) + matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None))) } /// Convert a non-generic crate item into an instance. diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 0810e327b63e3..6284754016aec 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -310,7 +310,7 @@ pub(crate) fn transform_instance<'tcx>( // FIXME: account for async-drop-glue if (matches!(instance.def, ty::InstanceKind::Virtual(..)) && tcx.is_lang_item(instance.def_id(), LangItem::DropGlue)) - || matches!(instance.def, ty::InstanceKind::DropGlue(..)) + || matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::DropGlue(..))) { // Adjust the type ids of DropGlues // @@ -364,7 +364,7 @@ pub(crate) fn transform_instance<'tcx>( tcx.types.unit }; instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1)); - } else if let ty::InstanceKind::VTableShim(def_id) = instance.def + } else if let ty::InstanceKind::Shim(ty::ShimKind::VTableShim(def_id)) = instance.def && let Some(trait_id) = tcx.trait_of_assoc(def_id) { // Adjust the type ids of VTableShims to the type id expected in the call sites for the @@ -461,7 +461,8 @@ pub(crate) fn transform_instance<'tcx>( fn default_or_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Option { match instance.def { - ty::InstanceKind::Item(def_id) | ty::InstanceKind::FnPtrShim(def_id, _) => { + ty::InstanceKind::Item(def_id) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(def_id, _)) => { tcx.opt_associated_item(def_id).map(|item| item.def_id) } _ => None, diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs index 3243e23fcf981..7df5ec9088a9c 100644 --- a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs +++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs @@ -6,7 +6,7 @@ use std::hash::Hasher; -use rustc_middle::ty::{Instance, InstanceKind, ReifyReason, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, InstanceKind, ReifyReason, ShimKind, Ty, TyCtxt}; use rustc_target::callconv::FnAbi; use twox_hash::XxHash64; @@ -46,7 +46,8 @@ pub fn typeid_for_instance<'tcx>( // // This was implemented for KCFI support in #123106 and #123052 (which introduced the // ReifyReason). The tracking issue for KCFI support for Rust is #123479. - if matches!(instance.def, InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr))) { + if matches!(instance.def, InstanceKind::Shim(ShimKind::ReifyShim(_, Some(ReifyReason::FnPtr)))) + { options.insert(TypeIdOptions::USE_CONCRETE_SELF); } // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index c13300a735c3c..d67b603b73a68 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -62,13 +62,13 @@ pub(super) fn mangle<'tcx>( let mut p = LegacySymbolMangler { tcx, path: SymbolPath::new(), keep_within_component: false }; p.print_def_path( def_id, - if let ty::InstanceKind::DropGlue(_, _) - | ty::InstanceKind::AsyncDropGlueCtorShim(_, _) - | ty::InstanceKind::FutureDropPollShim(_, _, _) = instance.def + if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, _)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, _)) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_, _, _)) = instance.def { // Add the name of the dropped type to the symbol name &*instance.args - } else if let ty::InstanceKind::AsyncDropGlue(_, ty) = instance.def { + } else if let ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_, ty)) = instance.def { let ty::Coroutine(_, cor_args) = ty.kind() else { bug!(); }; @@ -81,13 +81,13 @@ pub(super) fn mangle<'tcx>( .unwrap(); match instance.def { - ty::InstanceKind::ThreadLocalShim(..) => { + ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) => { p.write_str("{{tls-shim}}").unwrap(); } - ty::InstanceKind::VTableShim(..) => { + ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) => { p.write_str("{{vtable-shim}}").unwrap(); } - ty::InstanceKind::ReifyShim(_, reason) => { + ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, reason)) => { p.write_str("{{reify-shim").unwrap(); match reason { Some(ReifyReason::FnPtr) => p.write_str("-fnptr").unwrap(), @@ -98,14 +98,17 @@ pub(super) fn mangle<'tcx>( } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } => { + ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + receiver_by_ref, + .. + }) => { p.write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" }) .unwrap(); } _ => {} } - if let ty::InstanceKind::FutureDropPollShim(..) = instance.def { + if let ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) = instance.def { let _ = p.write_str("{{drop-shim}}"); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index c6624a7820559..b2f5ea1873807 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -49,25 +49,31 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { - ty::InstanceKind::ThreadLocalShim(_) => Some("tls"), - ty::InstanceKind::VTableShim(_) => Some("vtable"), - ty::InstanceKind::ReifyShim(_, None) => Some("reify"), - ty::InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"), - ty::InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"), + ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(_)) => Some("tls"), + ty::InstanceKind::Shim(ty::ShimKind::VTableShim(_)) => Some("vtable"), + ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, None)) => Some("reify"), + ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, Some(ReifyReason::FnPtr))) => { + Some("reify_fnptr") + } + ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, Some(ReifyReason::Vtable))) => { + Some("reify_vtable") + } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: true, .. } => { - Some("by_move") - } - ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: false, .. } => { - Some("by_ref") - } - ty::InstanceKind::FutureDropPollShim(_, _, _) => Some("drop"), + ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + receiver_by_ref: true, + .. + }) => Some("by_move"), + ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + receiver_by_ref: false, + .. + }) => Some("by_ref"), + ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_, _, _)) => Some("drop"), _ => None, }; - if let ty::InstanceKind::AsyncDropGlue(_, ty) = instance.def { + if let ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_, ty)) = instance.def { let ty::Coroutine(_, cor_args) = ty.kind() else { bug!(); }; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index e782557d126bf..d26750f255198 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -10,7 +10,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ FnAbiError, HasTyCtxt, HasTypingEnv, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind, }; -use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Unnormalized}; +use rustc_middle::ty::{self, InstanceKind, ShimKind, Ty, TyCtxt, Unnormalized}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; use rustc_target::callconv::{ @@ -38,7 +38,7 @@ fn fn_sig_for_fn_abi<'tcx>( instance: ty::Instance<'tcx>, typing_env: ty::TypingEnv<'tcx>, ) -> ty::FnSig<'tcx> { - if let InstanceKind::ThreadLocalShim(..) = instance.def { + if let InstanceKind::Shim(ShimKind::ThreadLocalShim(..)) = instance.def { return tcx.mk_fn_sig_safe_rust_abi([], tcx.thread_local_ptr_ty(instance.def_id())); } @@ -50,7 +50,7 @@ fn fn_sig_for_fn_abi<'tcx>( ); // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. - if let ty::InstanceKind::VTableShim(..) = instance.def { + if let ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) = instance.def { let mut inputs_and_output = sig.inputs_and_output.to_vec(); inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]); sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); @@ -82,22 +82,23 @@ fn fn_sig_for_fn_abi<'tcx>( // a separate def-id for these bodies. let mut coroutine_kind = args.as_coroutine_closure().kind(); - let env_ty = - if let InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } = - instance.def - { - coroutine_kind = ty::ClosureKind::FnOnce; - - // Implementations of `FnMut` and `Fn` for coroutine-closures - // still take their receiver by ref. - if receiver_by_ref { - Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty) - } else { - coroutine_ty - } + let env_ty = if let InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { + receiver_by_ref, + .. + }) = instance.def + { + coroutine_kind = ty::ClosureKind::FnOnce; + + // Implementations of `FnMut` and `Fn` for coroutine-closures + // still take their receiver by ref. + if receiver_by_ref { + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty) } else { - tcx.closure_env_ty(coroutine_ty, coroutine_kind, tcx.lifetimes.re_erased) - }; + coroutine_ty + } + } else { + tcx.closure_env_ty(coroutine_ty, coroutine_kind, tcx.lifetimes.re_erased) + }; let sig = tcx.instantiate_bound_regions_with_erased(sig); @@ -264,7 +265,8 @@ impl<'tcx> FnAbiDesc<'tcx> { ) -> Self { let ty::PseudoCanonicalInput { typing_env, value: (instance, extra_args) } = query; let is_virtual_call = matches!(instance.def, ty::InstanceKind::Virtual(..)); - let is_tls_shim_call = matches!(instance.def, ty::InstanceKind::ThreadLocalShim(_)); + let is_tls_shim_call = + matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(_))); Self { layout_cx: LayoutCx::new(tcx, typing_env), sig: tcx.normalize_erasing_regions( diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 7386afbe53771..25edafce89f13 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -38,16 +38,16 @@ fn resolve_instance_raw<'tcx>( } else if tcx.is_lang_item(def_id, LangItem::DropGlue) { let ty = args.type_at(0); - if ty.needs_drop(tcx, typing_env) { + let shim = if ty.needs_drop(tcx, typing_env) { debug!(" => nontrivial drop glue"); match *ty.kind() { ty::Coroutine(coroutine_def_id, ..) => { // FIXME: sync drop of coroutine with async drop (generate both versions?) // Currently just ignored if tcx.optimized_mir(coroutine_def_id).coroutine_drop_async().is_some() { - ty::InstanceKind::DropGlue(def_id, None) + ty::ShimKind::DropGlue(def_id, None) } else { - ty::InstanceKind::DropGlue(def_id, Some(ty)) + ty::ShimKind::DropGlue(def_id, Some(ty)) } } ty::Closure(..) @@ -57,14 +57,15 @@ fn resolve_instance_raw<'tcx>( | ty::Dynamic(..) | ty::Array(..) | ty::Slice(..) - | ty::UnsafeBinder(..) => ty::InstanceKind::DropGlue(def_id, Some(ty)), + | ty::UnsafeBinder(..) => ty::ShimKind::DropGlue(def_id, Some(ty)), // Drop shims can only be built from ADTs. _ => return Ok(None), } } else { debug!(" => trivial drop glue"); - ty::InstanceKind::DropGlue(def_id, None) - } + ty::ShimKind::DropGlue(def_id, None) + }; + ty::InstanceKind::Shim(shim) } else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) { let ty = args.type_at(0); @@ -82,14 +83,14 @@ fn resolve_instance_raw<'tcx>( _ => return Ok(None), } debug!(" => nontrivial async drop glue ctor"); - ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(def_id, ty)) } else { debug!(" => trivial async drop glue ctor"); - ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(def_id, ty)) } } else if tcx.is_async_drop_in_place_coroutine(def_id) { let ty = args.type_at(0); - ty::InstanceKind::AsyncDropGlue(def_id, ty) + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(def_id, ty)) } else { debug!(" => free item"); ty::InstanceKind::Item(def_id) @@ -279,7 +280,10 @@ fn resolve_associated_item<'tcx>( }; Some(Instance { - def: ty::InstanceKind::CloneShim(trait_item_id, self_ty), + def: ty::InstanceKind::Shim(ty::ShimKind::CloneShim( + trait_item_id, + self_ty, + )), args: rcvr_args, }) } else { @@ -296,7 +300,10 @@ fn resolve_associated_item<'tcx>( return Ok(None); } Some(Instance { - def: ty::InstanceKind::FnPtrAddrShim(trait_item_id, self_ty), + def: ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim( + trait_item_id, + self_ty, + )), args: rcvr_args, }) } else { @@ -326,7 +333,10 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), + def: ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim( + trait_item_id, + rcvr_args.type_at(0), + )), args: rcvr_args, }), ty::CoroutineClosure(coroutine_closure_def_id, args) => { @@ -339,10 +349,12 @@ fn resolve_associated_item<'tcx>( Some(Instance::new_raw(coroutine_closure_def_id, args)) } else { Some(Instance { - def: ty::InstanceKind::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - receiver_by_ref: target_kind != ty::ClosureKind::FnOnce, - }, + def: ty::InstanceKind::Shim( + ty::ShimKind::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + receiver_by_ref: target_kind != ty::ClosureKind::FnOnce, + }, + ), args, }) } @@ -362,10 +374,12 @@ fn resolve_associated_item<'tcx>( // If we're computing `AsyncFnOnce` for a by-ref closure then // construct a new body that has the right return types. Some(Instance { - def: ty::InstanceKind::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - receiver_by_ref: false, - }, + def: ty::InstanceKind::Shim( + ty::ShimKind::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + receiver_by_ref: false, + }, + ), args, }) } else { @@ -376,7 +390,10 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), + def: ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim( + trait_item_id, + rcvr_args.type_at(0), + )), args: rcvr_args, }), _ => bug!( From c329a0e6c966eda4b696f104a2a839841af9a5a4 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 18 Jun 2026 22:39:32 +0000 Subject: [PATCH 098/116] Strip vestigial `Shim` suffix from `ShimKind` variants --- .../rustc_codegen_cranelift/src/constant.rs | 2 +- .../src/back/symbol_export.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../rustc_const_eval/src/interpret/call.rs | 22 ++-- .../src/middle/codegen_fn_attrs.rs | 4 +- .../src/middle/exported_symbols.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 4 +- compiler/rustc_middle/src/mir/visit.rs | 20 +-- compiler/rustc_middle/src/mono.rs | 20 +-- compiler/rustc_middle/src/ty/instance.rs | 116 +++++++++--------- compiler/rustc_middle/src/ty/print/mod.rs | 26 ++-- compiler/rustc_mir_transform/src/inline.rs | 22 ++-- .../rustc_mir_transform/src/inline/cycle.rs | 20 +-- compiler/rustc_mir_transform/src/shim.rs | 39 +++--- .../src/shim/async_destructor_ctor.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 22 ++-- .../rustc_monomorphize/src/partitioning.rs | 44 ++++--- .../cfi/typeid/itanium_cxx_abi/transform.rs | 5 +- .../rustc_sanitizers/src/kcfi/typeid/mod.rs | 3 +- compiler/rustc_symbol_mangling/src/legacy.rs | 14 +-- compiler/rustc_symbol_mangling/src/v0.rs | 16 +-- compiler/rustc_ty_utils/src/abi.rs | 8 +- compiler/rustc_ty_utils/src/instance.rs | 19 ++- 23 files changed, 212 insertions(+), 224 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index a83bfd1cbad42..829e7d0dfb59c 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -53,7 +53,7 @@ pub(crate) fn codegen_tls_ref<'tcx>( ) -> CValue<'tcx> { let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(def_id)), args: ty::GenericArgs::empty(), }; let func_ref = fx.get_function_ref(instance); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 40d5c3b07059f..dfc8c8be5c03f 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -361,7 +361,7 @@ fn exported_generic_symbols_provider_local<'tcx>( } } MonoItem::Fn(Instance { - def: InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(_, ty)), + def: InstanceKind::Shim(ShimKind::AsyncDropGlueCtor(_, ty)), args, }) => { // A little sanity-check @@ -586,7 +586,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, ty::Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(def_id)), args: ty::GenericArgs::empty(), }, instantiating_crate, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index c1ee7c02e874e..5dc4617717c11 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -665,7 +665,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(def_id)), args: ty::GenericArgs::empty(), }; let fn_ptr = bx.get_fn_addr(instance); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 0236b49e497e4..44420b7148478 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -428,7 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Determine whether this is a non-capturing closure. That's relevant as their first // argument can be skipped (and that's the only kind of argument skipping we allow). let is_non_capturing_closure = - (matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. })) + (matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::ClosureOnce { .. })) || self.tcx.is_closure_like(def_id)) && { let arg = &callee_fn_abi.args[0]; @@ -652,18 +652,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } } - ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. }) - | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { .. }) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(..)) + ty::InstanceKind::Shim(ty::ShimKind::VTable(..)) + | ty::InstanceKind::Shim(ty::ShimKind::Reify(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnce { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtr(..)) | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(..)) - | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::Clone(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddr(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(..)) + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(..)) | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(..)) - | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(..)) | ty::InstanceKind::Item(_) => { // We need MIR for this fn. // Note that this can be an intrinsic, if we are executing its fallback body. diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index eefb346d174b4..713c6597c1966 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -33,7 +33,7 @@ impl<'tcx> TyCtxt<'tcx> { // // A `ClosureOnceShim` with the track_caller attribute does not have a symbol, // and therefore can be skipped here. - if let InstanceKind::Shim(ShimKind::ReifyShim(_, _)) = instance_kind + if let InstanceKind::Shim(ShimKind::Reify(_, _)) = instance_kind && attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) { if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { @@ -54,7 +54,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Ensure closure shims have the optimization properties of their closure applied to them. - if let InstanceKind::Shim(ShimKind::ClosureOnceShim { + if let InstanceKind::Shim(ShimKind::ClosureOnce { call_once: _, closure, track_caller: _, diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 5942f9dfa1def..e23ad3c832ef7 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -75,7 +75,7 @@ impl<'tcx> ExportedSymbol<'tcx> { tcx.symbol_name(ty::Instance::resolve_async_drop_in_place_poll(tcx, def_id, ty)) } ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(def_id)), + def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(def_id)), args: ty::GenericArgs::empty(), }), ExportedSymbol::NoDefId(symbol_name) => symbol_name, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 1c7d261dd5978..beab1b1a08e1a 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -229,7 +229,7 @@ impl<'a, 'tcx> MirDumper<'a, 'tcx> { })); s } - ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, ty)) => { + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(_, ty)) => { let mut s = ".".to_owned(); s.extend(ty.to_string().chars().filter_map(|c| match c { ' ' => None, @@ -251,7 +251,7 @@ impl<'a, 'tcx> MirDumper<'a, 'tcx> { })); s } - ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_, proxy_cor, impl_cor)) => { + ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(_, proxy_cor, impl_cor)) => { let mut s = ".".to_owned(); s.extend(proxy_cor.to_string().chars().filter_map(|c| match c { ' ' => None, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 35c47b761c5d4..921c54b2828c2 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -347,27 +347,27 @@ macro_rules! make_mir_visitor { ty::InstanceKind::Item(_def_id) => {} ty::InstanceKind::Intrinsic(_def_id) - | ty::InstanceKind::Shim(ty::ShimKind::VTableShim(_def_id)) - | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_def_id, _)) + | ty::InstanceKind::Shim(ty::ShimKind::VTable(_def_id)) + | ty::InstanceKind::Shim(ty::ShimKind::Reify(_def_id, _)) | ty::InstanceKind::Virtual(_def_id, _) - | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(_def_id)) - | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { call_once: _def_id, closure: _, track_caller: _ }) - | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(_def_id)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnce { call_once: _def_id, closure: _, track_caller: _ }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure { coroutine_closure_def_id: _def_id, receiver_by_ref: _, }) | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_def_id, None)) => {} - ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(_def_id, ty)) + ty::InstanceKind::Shim(ty::ShimKind::FnPtr(_def_id, ty)) | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_def_id, Some(ty))) - | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(_def_id, ty)) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(_def_id, ty)) + | ty::InstanceKind::Shim(ty::ShimKind::Clone(_def_id, ty)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddr(_def_id, ty)) | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_def_id, ty)) - | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_def_id, ty)) => { + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(_def_id, ty)) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } - ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_def_id, proxy_ty, impl_ty)) => { + ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(_def_id, proxy_ty, impl_ty)) => { self.visit_ty($(& $mutability)? *proxy_ty, TyContext::Location(location)); self.visit_ty($(& $mutability)? *impl_ty, TyContext::Location(location)); } diff --git a/compiler/rustc_middle/src/mono.rs b/compiler/rustc_middle/src/mono.rs index 054b3e9a49680..6df67257a2ea7 100644 --- a/compiler/rustc_middle/src/mono.rs +++ b/compiler/rustc_middle/src/mono.rs @@ -525,18 +525,18 @@ impl<'tcx> CodegenUnit<'tcx> { InstanceKind::Item(def) => def.as_local().map(|_| def), InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..) - | InstanceKind::Shim(ShimKind::VTableShim(..)) - | InstanceKind::Shim(ShimKind::ReifyShim(..)) - | InstanceKind::Shim(ShimKind::FnPtrShim(..)) - | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) - | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) + | InstanceKind::Shim(ShimKind::VTable(..)) + | InstanceKind::Shim(ShimKind::Reify(..)) + | InstanceKind::Shim(ShimKind::FnPtr(..)) + | InstanceKind::Shim(ShimKind::ClosureOnce { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosure { .. }) | InstanceKind::Shim(ShimKind::DropGlue(..)) - | InstanceKind::Shim(ShimKind::CloneShim(..)) - | InstanceKind::Shim(ShimKind::ThreadLocalShim(..)) - | InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) + | InstanceKind::Shim(ShimKind::Clone(..)) + | InstanceKind::Shim(ShimKind::ThreadLocal(..)) + | InstanceKind::Shim(ShimKind::FnPtrAddr(..)) | InstanceKind::Shim(ShimKind::AsyncDropGlue(..)) - | InstanceKind::Shim(ShimKind::FutureDropPollShim(..)) - | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(..)) => None, + | InstanceKind::Shim(ShimKind::FutureDropPoll(..)) + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtor(..)) => None, }, MonoItem::Static(def_id) => def_id.as_local().map(|_| def_id), MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.to_def_id()), diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 2fc2a4a23c88c..30c299aa82b1a 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -96,7 +96,7 @@ pub enum ShimKind<'tcx> { /// /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` - /// and dereference the argument to call the original function. - VTableShim(DefId), + VTable(DefId), /// `fn()` pointer where the function itself cannot be turned into a pointer. /// @@ -115,12 +115,12 @@ pub enum ShimKind<'tcx> { /// /// This field will only be populated if we are compiling in a mode that needs these shims /// to be separable, currently only when KCFI is enabled. - ReifyShim(DefId, Option), + Reify(DefId, Option), /// `::call_*` (generated `FnTrait` implementation for `fn()` pointers). /// /// `DefId` is `FnTrait::call_*`. - FnPtrShim(DefId, Ty<'tcx>), + FnPtr(DefId, Ty<'tcx>), /// `<[FnMut/Fn closure] as FnOnce>::call_once`. /// @@ -128,14 +128,14 @@ pub enum ShimKind<'tcx> { /// /// This generates a body that will just borrow the (owned) self type, /// and dispatch to the `FnMut::call_mut` instance for the closure. - ClosureOnceShim { call_once: DefId, closure: DefId, track_caller: bool }, + ClosureOnce { call_once: DefId, closure: DefId, track_caller: bool }, /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` /// /// The body generated here differs significantly from the `ClosureOnceShim`, /// since we need to generate a distinct coroutine type that will move the /// closure's upvars *out* of the closure. - ConstructCoroutineInClosureShim { + ConstructCoroutineInClosure { coroutine_closure_def_id: DefId, // Whether the generated MIR body takes the coroutine by-ref. This is // because the signature of `<{async fn} as FnMut>::call_mut` is: @@ -148,10 +148,10 @@ pub enum ShimKind<'tcx> { /// Compiler-generated accessor for thread locals which returns a reference to the thread local /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking /// native support. - ThreadLocalShim(DefId), + ThreadLocal(DefId), /// Proxy shim for async drop of future (def_id, proxy_cor_ty, impl_cor_ty) - FutureDropPollShim(DefId, Ty<'tcx>, Ty<'tcx>), + FutureDropPoll(DefId, Ty<'tcx>, Ty<'tcx>), /// `core::ptr::drop_glue::`. /// @@ -168,20 +168,20 @@ pub enum ShimKind<'tcx> { /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`. /// /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl. - CloneShim(DefId, Ty<'tcx>), + Clone(DefId, Ty<'tcx>), /// Compiler-generated `::addr` implementation. /// /// Automatically generated for all potentially higher-ranked `fn(I) -> R` types. /// /// The `DefId` is for `FnPtr::addr`, the `Ty` is the type `T`. - FnPtrAddrShim(DefId, Ty<'tcx>), + FnPtrAddr(DefId, Ty<'tcx>), /// `core::future::async_drop::async_drop_in_place::<'_, T>`. /// /// The `DefId` is for `core::future::async_drop::async_drop_in_place`, the `Ty` /// is the type `T`. - AsyncDropGlueCtorShim(DefId, Ty<'tcx>), + AsyncDropGlueCtor(DefId, Ty<'tcx>), /// `core::future::async_drop::async_drop_in_place::<'_, T>::{closure}`. /// @@ -238,8 +238,8 @@ impl<'tcx> Instance<'tcx> { tcx.upstream_drop_glue_for(self.args) } InstanceKind::Shim(ShimKind::AsyncDropGlue(_, _)) => None, - InstanceKind::Shim(ShimKind::FutureDropPollShim(_, _, _)) => None, - InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(_, _)) => { + InstanceKind::Shim(ShimKind::FutureDropPoll(_, _, _)) => None, + InstanceKind::Shim(ShimKind::AsyncDropGlueCtor(_, _)) => { tcx.upstream_async_drop_glue_for(self.args) } _ => None, @@ -288,10 +288,10 @@ impl<'tcx> InstanceKind<'tcx> { match *self { InstanceKind::Item(def_id) | InstanceKind::Virtual(def_id, _) - | InstanceKind::Shim(ShimKind::VTableShim(def_id)) => { + | InstanceKind::Shim(ShimKind::VTable(def_id)) => { tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } - InstanceKind::Shim(ShimKind::ClosureOnceShim { + InstanceKind::Shim(ShimKind::ClosureOnce { call_once: _, closure: _, track_caller, @@ -318,21 +318,21 @@ impl<'tcx> ShimKind<'tcx> { #[inline] pub fn def_id(self) -> DefId { match self { - ShimKind::VTableShim(def_id) - | ShimKind::ReifyShim(def_id, _) - | ShimKind::FnPtrShim(def_id, _) - | ShimKind::ThreadLocalShim(def_id) - | ShimKind::ClosureOnceShim { call_once: def_id, closure: _, track_caller: _ } - | ShimKind::ConstructCoroutineInClosureShim { + ShimKind::VTable(def_id) + | ShimKind::Reify(def_id, _) + | ShimKind::FnPtr(def_id, _) + | ShimKind::ThreadLocal(def_id) + | ShimKind::ClosureOnce { call_once: def_id, closure: _, track_caller: _ } + | ShimKind::ConstructCoroutineInClosure { coroutine_closure_def_id: def_id, receiver_by_ref: _, } | ShimKind::DropGlue(def_id, _) - | ShimKind::CloneShim(def_id, _) - | ShimKind::FnPtrAddrShim(def_id, _) - | ShimKind::FutureDropPollShim(def_id, _, _) + | ShimKind::Clone(def_id, _) + | ShimKind::FnPtrAddr(def_id, _) + | ShimKind::FutureDropPoll(def_id, _, _) | ShimKind::AsyncDropGlue(def_id, _) - | ShimKind::AsyncDropGlueCtorShim(def_id, _) => def_id, + | ShimKind::AsyncDropGlueCtor(def_id, _) => def_id, } } @@ -340,47 +340,47 @@ impl<'tcx> ShimKind<'tcx> { pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { match self { ShimKind::DropGlue(def_id, Some(_)) - | ShimKind::AsyncDropGlueCtorShim(def_id, _) + | ShimKind::AsyncDropGlueCtor(def_id, _) | ShimKind::AsyncDropGlue(def_id, _) - | ShimKind::FutureDropPollShim(def_id, ..) - | ShimKind::ThreadLocalShim(def_id) => Some(def_id), - ShimKind::VTableShim(..) - | ShimKind::ReifyShim(..) - | ShimKind::FnPtrShim(..) - | ShimKind::ClosureOnceShim { .. } - | ShimKind::ConstructCoroutineInClosureShim { .. } + | ShimKind::FutureDropPoll(def_id, ..) + | ShimKind::ThreadLocal(def_id) => Some(def_id), + ShimKind::VTable(..) + | ShimKind::Reify(..) + | ShimKind::FnPtr(..) + | ShimKind::ClosureOnce { .. } + | ShimKind::ConstructCoroutineInClosure { .. } | ShimKind::DropGlue(..) - | ShimKind::CloneShim(..) - | ShimKind::FnPtrAddrShim(..) => None, + | ShimKind::Clone(..) + | ShimKind::FnPtrAddr(..) => None, } } pub fn requires_inline(&self) -> bool { match self { ShimKind::DropGlue(_, Some(ty)) => ty.is_array(), - ShimKind::AsyncDropGlueCtorShim(_, ty) => ty.is_coroutine(), - ShimKind::FutureDropPollShim(_, _, _) => false, + ShimKind::AsyncDropGlueCtor(_, ty) => ty.is_coroutine(), + ShimKind::FutureDropPoll(_, _, _) => false, ShimKind::AsyncDropGlue(_, _) => false, - ShimKind::ThreadLocalShim(_) => false, + ShimKind::ThreadLocal(_) => false, _ => true, } } pub fn has_polymorphic_mir_body(&self) -> bool { match *self { - ShimKind::CloneShim(..) - | ShimKind::ThreadLocalShim(..) - | ShimKind::FnPtrAddrShim(..) - | ShimKind::FnPtrShim(..) + ShimKind::Clone(..) + | ShimKind::ThreadLocal(..) + | ShimKind::FnPtrAddr(..) + | ShimKind::FnPtr(..) | ShimKind::DropGlue(_, Some(_)) - | ShimKind::FutureDropPollShim(..) + | ShimKind::FutureDropPoll(..) | ShimKind::AsyncDropGlue(_, _) => false, - ShimKind::AsyncDropGlueCtorShim(_, _) => false, - ShimKind::ClosureOnceShim { .. } - | ShimKind::ConstructCoroutineInClosureShim { .. } + ShimKind::AsyncDropGlueCtor(_, _) => false, + ShimKind::ClosureOnce { .. } + | ShimKind::ConstructCoroutineInClosure { .. } | ShimKind::DropGlue(..) - | ShimKind::ReifyShim(..) - | ShimKind::VTableShim(..) => true, + | ShimKind::Reify(..) + | ShimKind::VTable(..) => true, } } } @@ -451,7 +451,7 @@ fn resolve_async_drop_poll<'tcx>(mut cor_ty: Ty<'tcx>) -> Instance<'tcx> { continue; } else { return Instance { - def: ty::InstanceKind::Shim(ShimKind::FutureDropPollShim( + def: ty::InstanceKind::Shim(ShimKind::FutureDropPoll( poll_def_id, first_cor, cor_ty, @@ -465,7 +465,7 @@ fn resolve_async_drop_poll<'tcx>(mut cor_ty: Ty<'tcx>) -> Instance<'tcx> { }; if first_cor != cor_ty { return Instance { - def: ty::InstanceKind::Shim(ShimKind::FutureDropPollShim( + def: ty::InstanceKind::Shim(ShimKind::FutureDropPoll( poll_def_id, first_cor, cor_ty, @@ -642,11 +642,11 @@ impl<'tcx> Instance<'tcx> { match resolved.def { InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def, reason)); + resolved.def = InstanceKind::Shim(ShimKind::Reify(def, reason)); } InstanceKind::Virtual(def_id, _) => { debug!(" => fn pointer created for virtual call"); - resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)); + resolved.def = InstanceKind::Shim(ShimKind::Reify(def_id, reason)); } _ if tcx.sess.is_sanitizer_kcfi_enabled() => { // Reify `::call`-like method implementations @@ -655,7 +655,7 @@ impl<'tcx> Instance<'tcx> { // be directly reified because it's closure-like. The reify can handle the // unresolved instance. resolved = Instance { - def: InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)), + def: InstanceKind::Shim(ShimKind::Reify(def_id, reason)), args, } // Reify `Trait::method` implementations if the trait is dyn-compatible. @@ -667,7 +667,7 @@ impl<'tcx> Instance<'tcx> { // If this function could also go in a vtable, we need to `ReifyShim` it with // KCFI because it can only attach one type per function. resolved.def = - InstanceKind::Shim(ShimKind::ReifyShim(resolved.def_id(), reason)) + InstanceKind::Shim(ShimKind::Reify(resolved.def_id(), reason)) } } _ => {} @@ -692,7 +692,7 @@ impl<'tcx> Instance<'tcx> { if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - return Instance { def: InstanceKind::Shim(ShimKind::VTableShim(def_id)), args }; + return Instance { def: InstanceKind::Shim(ShimKind::VTable(def_id)), args }; } let mut resolved = Instance::expect_resolve(tcx, typing_env, def_id, args, span); @@ -736,7 +736,7 @@ impl<'tcx> Instance<'tcx> { // - unlike functions, invoking a closure always goes through a // trait. resolved = Instance { - def: InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)), + def: InstanceKind::Shim(ShimKind::Reify(def_id, reason)), args, }; } else { @@ -744,13 +744,13 @@ impl<'tcx> Instance<'tcx> { " => vtable fn pointer created for function with #[track_caller]: {:?}", def ); - resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def, reason)); + resolved.def = InstanceKind::Shim(ShimKind::Reify(def, reason)); } } } InstanceKind::Virtual(def_id, _) => { debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceKind::Shim(ShimKind::ReifyShim(def_id, reason)) + resolved.def = InstanceKind::Shim(ShimKind::Reify(def_id, reason)) } _ => {} } @@ -820,7 +820,7 @@ impl<'tcx> Instance<'tcx> { .def_id; let track_caller = tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); - let def = ty::InstanceKind::Shim(ShimKind::ClosureOnceShim { + let def = ty::InstanceKind::Shim(ShimKind::ClosureOnce { call_once, closure: closure_did, track_caller, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 0552bf1dd1636..bec1ffc642769 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -381,29 +381,27 @@ impl<'tcx, P: Printer<'tcx> + std::fmt::Write> Print

for ty::Instance<'tcx> { impl<'tcx, P: Printer<'tcx> + std::fmt::Write> Print

for ty::ShimKind<'tcx> { fn print(&self, cx: &mut P) -> Result<(), PrintError> { match self { - ty::ShimKind::VTableShim(_) => cx.write_str("shim(vtable)"), - ty::ShimKind::ReifyShim(_, None) => cx.write_str("shim(reify)"), - ty::ShimKind::ReifyShim(_, Some(ty::ReifyReason::FnPtr)) => { + ty::ShimKind::VTable(_) => cx.write_str("shim(vtable)"), + ty::ShimKind::Reify(_, None) => cx.write_str("shim(reify)"), + ty::ShimKind::Reify(_, Some(ty::ReifyReason::FnPtr)) => { cx.write_str("shim(reify-fnptr)") } - ty::ShimKind::ReifyShim(_, Some(ty::ReifyReason::Vtable)) => { + ty::ShimKind::Reify(_, Some(ty::ReifyReason::Vtable)) => { cx.write_str("shim(reify-vtable)") } - ty::ShimKind::ThreadLocalShim(_) => cx.write_str("shim(tls)"), - ty::ShimKind::FnPtrShim(_, ty) => cx.write_str(&format!("shim({ty})")), - ty::ShimKind::ClosureOnceShim { .. } => cx.write_str("shim"), - ty::ShimKind::ConstructCoroutineInClosureShim { .. } => cx.write_str("shim"), + ty::ShimKind::ThreadLocal(_) => cx.write_str("shim(tls)"), + ty::ShimKind::FnPtr(_, ty) => cx.write_str(&format!("shim({ty})")), + ty::ShimKind::ClosureOnce { .. } => cx.write_str("shim"), + ty::ShimKind::ConstructCoroutineInClosure { .. } => cx.write_str("shim"), ty::ShimKind::DropGlue(_, None) => cx.write_str("shim(None)"), ty::ShimKind::DropGlue(_, Some(ty)) => cx.write_str(&format!("shim(Some({ty}))")), - ty::ShimKind::CloneShim(_, ty) => cx.write_str(&format!("shim({ty})")), - ty::ShimKind::FnPtrAddrShim(_, ty) => cx.write_str(&format!("shim({ty})")), - ty::ShimKind::FutureDropPollShim(_, proxy_ty, impl_ty) => { + ty::ShimKind::Clone(_, ty) => cx.write_str(&format!("shim({ty})")), + ty::ShimKind::FnPtrAddr(_, ty) => cx.write_str(&format!("shim({ty})")), + ty::ShimKind::FutureDropPoll(_, proxy_ty, impl_ty) => { cx.write_str(&format!("dropshim({proxy_ty}-{impl_ty})")) } ty::ShimKind::AsyncDropGlue(_, ty) => cx.write_str(&format!("shim({ty})")), - ty::ShimKind::AsyncDropGlueCtorShim(_, ty) => { - cx.write_str(&format!("shim(Some({ty}))")) - } + ty::ShimKind::AsyncDropGlueCtor(_, ty) => cx.write_str(&format!("shim(Some({ty}))")), } } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index a1575a21e9073..e4ce2fb1ad3d2 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -746,14 +746,14 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( return Err("implementation limitation -- HACK for dropping polymorphic type"); } InstanceKind::Shim(ShimKind::AsyncDropGlue(_, ty)) - | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(_, ty)) => { + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtor(_, ty)) => { return if ty.still_further_specializable() { Err("still needs substitution") } else { Ok(()) }; } - InstanceKind::Shim(ShimKind::FutureDropPollShim(_, ty, ty2)) => { + InstanceKind::Shim(ShimKind::FutureDropPoll(_, ty, ty2)) => { return if ty.still_further_specializable() || ty2.still_further_specializable() { Err("still needs substitution") } else { @@ -765,15 +765,15 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. - InstanceKind::Shim(ShimKind::VTableShim(_)) - | InstanceKind::Shim(ShimKind::ReifyShim(..)) - | InstanceKind::Shim(ShimKind::FnPtrShim(..)) - | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) - | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) + InstanceKind::Shim(ShimKind::VTable(_)) + | InstanceKind::Shim(ShimKind::Reify(..)) + | InstanceKind::Shim(ShimKind::FnPtr(..)) + | InstanceKind::Shim(ShimKind::ClosureOnce { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosure { .. }) | InstanceKind::Shim(ShimKind::DropGlue(..)) - | InstanceKind::Shim(ShimKind::CloneShim(..)) - | InstanceKind::Shim(ShimKind::ThreadLocalShim(..)) - | InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) => return Ok(()), + | InstanceKind::Shim(ShimKind::Clone(..)) + | InstanceKind::Shim(ShimKind::ThreadLocal(..)) + | InstanceKind::Shim(ShimKind::FnPtrAddr(..)) => return Ok(()), } if inliner.tcx().is_constructor(callee_def_id) { @@ -1374,7 +1374,7 @@ fn try_instance_mir<'tcx>( instance: InstanceKind<'tcx>, ) -> Result<&'tcx Body<'tcx>, &'static str> { if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, Some(ty))) - | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, ty)) = instance + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(_, ty)) = instance && let ty::Adt(def, args) = ty.kind() { let fields = def.all_fields(); diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 0fd1a5f240758..ee63dd966baf6 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -26,24 +26,24 @@ fn should_recurse<'tcx>(tcx: TyCtxt<'tcx>, callee: ty::Instance<'tcx>) -> bool { // These have MIR and if that MIR is inlined, instantiated and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way - InstanceKind::Shim(ShimKind::VTableShim(_)) - | InstanceKind::Shim(ShimKind::ReifyShim(..)) - | InstanceKind::Shim(ShimKind::FnPtrShim(..)) - | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) - | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) - | InstanceKind::Shim(ShimKind::ThreadLocalShim { .. }) - | InstanceKind::Shim(ShimKind::CloneShim(..)) => {} + InstanceKind::Shim(ShimKind::VTable(_)) + | InstanceKind::Shim(ShimKind::Reify(..)) + | InstanceKind::Shim(ShimKind::FnPtr(..)) + | InstanceKind::Shim(ShimKind::ClosureOnce { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosure { .. }) + | InstanceKind::Shim(ShimKind::ThreadLocal { .. }) + | InstanceKind::Shim(ShimKind::Clone(..)) => {} // This shim does not call any other functions, thus there can be no recursion. - InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) => return false, + InstanceKind::Shim(ShimKind::FnPtrAddr(..)) => return false, // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. InstanceKind::Shim(ShimKind::DropGlue(..)) - | InstanceKind::Shim(ShimKind::FutureDropPollShim(..)) + | InstanceKind::Shim(ShimKind::FutureDropPoll(..)) | InstanceKind::Shim(ShimKind::AsyncDropGlue(..)) - | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(..)) => { + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtor(..)) => { if callee.has_param() { return false; } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index d6061edb74ce3..436b99811ae60 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -35,11 +35,11 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Body<'tcx> { debug!("make_shim({:?})", shim); let mut result = match shim { - ty::ShimKind::VTableShim(def_id) => { + ty::ShimKind::VTable(def_id) => { let adjustment = Adjustment::Deref { source: DerefSource::MutPtr }; build_call_shim(tcx, shim, Some(adjustment), CallKind::Direct(def_id)) } - ty::ShimKind::FnPtrShim(def_id, ty) => { + ty::ShimKind::FnPtr(def_id, ty) => { let trait_ = tcx.parent(def_id); // Supports `Fn` or `async Fn` traits. let adjustment = match tcx @@ -59,10 +59,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Body<'tcx> { // a virtual call, or a direct call to a function for which // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). - ty::ShimKind::ReifyShim(def_id, _) => { + ty::ShimKind::Reify(def_id, _) => { build_call_shim(tcx, shim, None, CallKind::Direct(def_id)) } - ty::ShimKind::ClosureOnceShim { call_once: _, closure: _, track_caller: _ } => { + ty::ShimKind::ClosureOnce { call_once: _, closure: _, track_caller: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP); let call_mut = tcx .associated_items(fn_mut) @@ -74,10 +74,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Body<'tcx> { build_call_shim(tcx, shim, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } - ty::ShimKind::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - receiver_by_ref, - } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), + ty::ShimKind::ConstructCoroutineInClosure { coroutine_closure_def_id, receiver_by_ref } => { + build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref) + } ty::ShimKind::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end @@ -128,10 +127,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Body<'tcx> { build_drop_shim(tcx, def_id, ty, ty::TypingEnv::post_analysis(tcx, def_id)) } - ty::ShimKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, shim), - ty::ShimKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), - ty::ShimKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), - ty::ShimKind::FutureDropPollShim(def_id, proxy_ty, impl_ty) => { + ty::ShimKind::ThreadLocal(..) => build_thread_local_shim(tcx, shim), + ty::ShimKind::Clone(def_id, ty) => build_clone_shim(tcx, def_id, ty), + ty::ShimKind::FnPtrAddr(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), + ty::ShimKind::FutureDropPoll(def_id, proxy_ty, impl_ty) => { let mut body = async_destructor_ctor::build_future_drop_poll_shim(tcx, def_id, proxy_ty, impl_ty); @@ -173,7 +172,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, shim: ty::ShimKind<'tcx>) -> Body<'tcx> { return body; } - ty::ShimKind::AsyncDropGlueCtorShim(def_id, ty) => { + ty::ShimKind::AsyncDropGlueCtor(def_id, ty) => { let body = async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty); debug!("make_shim({:?}) = {:?}", shim, body); return body; @@ -555,10 +554,8 @@ impl<'tcx> CloneShimBuilder<'tcx> { } fn into_mir(self) -> Body<'tcx> { - let source = MirSource::from_shim(ty::ShimKind::CloneShim( - self.def_id, - self.sig.inputs_and_output[0], - )); + let source = + MirSource::from_shim(ty::ShimKind::Clone(self.def_id, self.sig.inputs_and_output[0])); new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span) } @@ -773,7 +770,7 @@ fn build_call_shim<'tcx>( // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used // to instantiate into the signature of the shim. It is not necessary for users of this // MIR body to perform further instantiations (see `InstanceKind::has_polymorphic_mir_body`). - let (sig_args, untuple_args) = if let ty::ShimKind::FnPtrShim(_, ty) = shim { + let (sig_args, untuple_args) = if let ty::ShimKind::FnPtr(_, ty) = shim { let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx)); let untuple_args = sig.inputs(); @@ -827,7 +824,7 @@ fn build_call_shim<'tcx>( // FIXME: Avoid having to adjust the signature both here and in // `fn_sig_for_fn_abi`. - if let ty::ShimKind::VTableShim(..) = shim { + if let ty::ShimKind::VTable(..) = shim { // Modify fn(self, ...) to fn(self: *mut Self, ...) let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; @@ -1109,7 +1106,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t Some(Terminator { source_info, kind: TerminatorKind::Return, attributes: ThinVec::new() }), false, ); - let source = MirSource::from_shim(ty::ShimKind::FnPtrAddrShim(def_id, self_ty)); + let source = MirSource::from_shim(ty::ShimKind::FnPtrAddr(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } @@ -1208,7 +1205,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>( false, ); - let source = MirSource::from_shim(ty::ShimKind::ConstructCoroutineInClosureShim { + let source = MirSource::from_shim(ty::ShimKind::ConstructCoroutineInClosure { coroutine_closure_def_id, receiver_by_ref, }); diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index b23ab7842d51f..f6217f1234bfc 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -175,7 +175,7 @@ pub(super) fn build_future_drop_poll_shim<'tcx>( proxy_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, ) -> Body<'tcx> { - let shim = ty::ShimKind::FutureDropPollShim(def_id, proxy_ty, impl_ty); + let shim = ty::ShimKind::FutureDropPoll(def_id, proxy_ty, impl_ty); let ty::Coroutine(coroutine_def_id, _) = impl_ty.kind() else { bug!("build_future_drop_poll_shim not for coroutine impl type: ({:?})", shim); }; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 7c4fce02ff005..20aaeba4c8c65 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -447,7 +447,7 @@ fn collect_items_rec<'tcx>( used_items.push(respan( starting_item.span, MonoItem::Fn(Instance { - def: InstanceKind::Shim(ShimKind::ThreadLocalShim(def_id)), + def: InstanceKind::Shim(ShimKind::ThreadLocal(def_id)), args: GenericArgs::empty(), }), )); @@ -1013,7 +1013,7 @@ fn visit_instance_use<'tcx>( bug!("{:?} being reified", instance); } } - ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) => { + ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(..)) => { bug!("{:?} being reified", instance); } ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None)) => { @@ -1027,16 +1027,16 @@ fn visit_instance_use<'tcx>( } ty::InstanceKind::Item(..) | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, Some(_))) - | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(..)) | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(_, _)) - | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, _)) - | ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. }) - | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { .. }) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(..)) => { + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(_, _)) + | ty::InstanceKind::Shim(ty::ShimKind::VTable(..)) + | ty::InstanceKind::Shim(ty::ShimKind::Reify(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnce { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtr(..)) + | ty::InstanceKind::Shim(ty::ShimKind::Clone(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddr(..)) => { output.push(create_fn_mono_item(tcx, instance, source)); } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 79b47c8e5944d..bf4a2bdd15107 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -632,20 +632,18 @@ fn characteristic_def_id_of_mono_item<'tcx>( ty::InstanceKind::Item(def) => def, ty::InstanceKind::Intrinsic(..) | ty::InstanceKind::Virtual(..) - | ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnceShim { .. }) - | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { - .. - }) + | ty::InstanceKind::Shim(ty::ShimKind::VTable(..)) + | ty::InstanceKind::Shim(ty::ShimKind::Reify(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtr(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ClosureOnce { .. }) + | ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure { .. }) | ty::InstanceKind::Shim(ty::ShimKind::DropGlue(..)) - | ty::InstanceKind::Shim(ty::ShimKind::CloneShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim(..)) - | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) + | ty::InstanceKind::Shim(ty::ShimKind::Clone(..)) + | ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddr(..)) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(..)) | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlue(..)) - | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(..)) => return None, + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(..)) => return None, }; // If this is a method, we want to put it into the same module as @@ -797,26 +795,26 @@ fn mono_item_visibility<'tcx>( let def_id = match instance.def { InstanceKind::Item(def_id) | InstanceKind::Shim(ShimKind::DropGlue(def_id, Some(_))) - | InstanceKind::Shim(ShimKind::FutureDropPollShim(def_id, _, _)) + | InstanceKind::Shim(ShimKind::FutureDropPoll(def_id, _, _)) | InstanceKind::Shim(ShimKind::AsyncDropGlue(def_id, _)) - | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(def_id, _)) => def_id, + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtor(def_id, _)) => def_id, // We match the visibility of statics here - InstanceKind::Shim(ShimKind::ThreadLocalShim(def_id)) => { + InstanceKind::Shim(ShimKind::ThreadLocal(def_id)) => { return static_visibility(tcx, can_be_internalized, def_id); } // These are all compiler glue and such, never exported, always hidden. - InstanceKind::Shim(ShimKind::VTableShim(..)) - | InstanceKind::Shim(ShimKind::ReifyShim(..)) - | InstanceKind::Shim(ShimKind::FnPtrShim(..)) + InstanceKind::Shim(ShimKind::VTable(..)) + | InstanceKind::Shim(ShimKind::Reify(..)) + | InstanceKind::Shim(ShimKind::FnPtr(..)) | InstanceKind::Virtual(..) | InstanceKind::Intrinsic(..) - | InstanceKind::Shim(ShimKind::ClosureOnceShim { .. }) - | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { .. }) + | InstanceKind::Shim(ShimKind::ClosureOnce { .. }) + | InstanceKind::Shim(ShimKind::ConstructCoroutineInClosure { .. }) | InstanceKind::Shim(ShimKind::DropGlue(..)) - | InstanceKind::Shim(ShimKind::CloneShim(..)) - | InstanceKind::Shim(ShimKind::FnPtrAddrShim(..)) => return Visibility::Hidden, + | InstanceKind::Shim(ShimKind::Clone(..)) + | InstanceKind::Shim(ShimKind::FnPtrAddr(..)) => return Visibility::Hidden, }; // Both the `start_fn` lang item and `main` itself should not be exported, @@ -1334,7 +1332,7 @@ pub(crate) fn provide(providers: &mut Providers) { // statements, plus one for the terminator. InstanceKind::Item(..) | InstanceKind::Shim(ShimKind::DropGlue(..)) - | InstanceKind::Shim(ShimKind::AsyncDropGlueCtorShim(..)) => { + | InstanceKind::Shim(ShimKind::AsyncDropGlueCtor(..)) => { let mir = tcx.instance_mir(instance.def); mir.basic_blocks .iter() diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 6284754016aec..e901e1cf98e7e 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -364,7 +364,7 @@ pub(crate) fn transform_instance<'tcx>( tcx.types.unit }; instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1)); - } else if let ty::InstanceKind::Shim(ty::ShimKind::VTableShim(def_id)) = instance.def + } else if let ty::InstanceKind::Shim(ty::ShimKind::VTable(def_id)) = instance.def && let Some(trait_id) = tcx.trait_of_assoc(def_id) { // Adjust the type ids of VTableShims to the type id expected in the call sites for the @@ -461,8 +461,7 @@ pub(crate) fn transform_instance<'tcx>( fn default_or_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Option { match instance.def { - ty::InstanceKind::Item(def_id) - | ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim(def_id, _)) => { + ty::InstanceKind::Item(def_id) | ty::InstanceKind::Shim(ty::ShimKind::FnPtr(def_id, _)) => { tcx.opt_associated_item(def_id).map(|item| item.def_id) } _ => None, diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs index 7df5ec9088a9c..23aa088c68ffa 100644 --- a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs +++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs @@ -46,8 +46,7 @@ pub fn typeid_for_instance<'tcx>( // // This was implemented for KCFI support in #123106 and #123052 (which introduced the // ReifyReason). The tracking issue for KCFI support for Rust is #123479. - if matches!(instance.def, InstanceKind::Shim(ShimKind::ReifyShim(_, Some(ReifyReason::FnPtr)))) - { + if matches!(instance.def, InstanceKind::Shim(ShimKind::Reify(_, Some(ReifyReason::FnPtr)))) { options.insert(TypeIdOptions::USE_CONCRETE_SELF); } // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index d67b603b73a68..2513e7f958a21 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -63,8 +63,8 @@ pub(super) fn mangle<'tcx>( p.print_def_path( def_id, if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, _)) - | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(_, _)) - | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_, _, _)) = instance.def + | ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(_, _)) + | ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(_, _, _)) = instance.def { // Add the name of the dropped type to the symbol name &*instance.args @@ -81,13 +81,13 @@ pub(super) fn mangle<'tcx>( .unwrap(); match instance.def { - ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(..)) => { + ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(..)) => { p.write_str("{{tls-shim}}").unwrap(); } - ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) => { + ty::InstanceKind::Shim(ty::ShimKind::VTable(..)) => { p.write_str("{{vtable-shim}}").unwrap(); } - ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, reason)) => { + ty::InstanceKind::Shim(ty::ShimKind::Reify(_, reason)) => { p.write_str("{{reify-shim").unwrap(); match reason { Some(ReifyReason::FnPtr) => p.write_str("-fnptr").unwrap(), @@ -98,7 +98,7 @@ pub(super) fn mangle<'tcx>( } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure { receiver_by_ref, .. }) => { @@ -108,7 +108,7 @@ pub(super) fn mangle<'tcx>( _ => {} } - if let ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(..)) = instance.def { + if let ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(..)) = instance.def { let _ = p.write_str("{{drop-shim}}"); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index b2f5ea1873807..b259774468c91 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -49,27 +49,27 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { - ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(_)) => Some("tls"), - ty::InstanceKind::Shim(ty::ShimKind::VTableShim(_)) => Some("vtable"), - ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, None)) => Some("reify"), - ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, Some(ReifyReason::FnPtr))) => { + ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(_)) => Some("tls"), + ty::InstanceKind::Shim(ty::ShimKind::VTable(_)) => Some("vtable"), + ty::InstanceKind::Shim(ty::ShimKind::Reify(_, None)) => Some("reify"), + ty::InstanceKind::Shim(ty::ShimKind::Reify(_, Some(ReifyReason::FnPtr))) => { Some("reify_fnptr") } - ty::InstanceKind::Shim(ty::ShimKind::ReifyShim(_, Some(ReifyReason::Vtable))) => { + ty::InstanceKind::Shim(ty::ShimKind::Reify(_, Some(ReifyReason::Vtable))) => { Some("reify_vtable") } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure { receiver_by_ref: true, .. }) => Some("by_move"), - ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosureShim { + ty::InstanceKind::Shim(ty::ShimKind::ConstructCoroutineInClosure { receiver_by_ref: false, .. }) => Some("by_ref"), - ty::InstanceKind::Shim(ty::ShimKind::FutureDropPollShim(_, _, _)) => Some("drop"), + ty::InstanceKind::Shim(ty::ShimKind::FutureDropPoll(_, _, _)) => Some("drop"), _ => None, }; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index d26750f255198..1d24dba913bcb 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -38,7 +38,7 @@ fn fn_sig_for_fn_abi<'tcx>( instance: ty::Instance<'tcx>, typing_env: ty::TypingEnv<'tcx>, ) -> ty::FnSig<'tcx> { - if let InstanceKind::Shim(ShimKind::ThreadLocalShim(..)) = instance.def { + if let InstanceKind::Shim(ShimKind::ThreadLocal(..)) = instance.def { return tcx.mk_fn_sig_safe_rust_abi([], tcx.thread_local_ptr_ty(instance.def_id())); } @@ -50,7 +50,7 @@ fn fn_sig_for_fn_abi<'tcx>( ); // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. - if let ty::InstanceKind::Shim(ty::ShimKind::VTableShim(..)) = instance.def { + if let ty::InstanceKind::Shim(ty::ShimKind::VTable(..)) = instance.def { let mut inputs_and_output = sig.inputs_and_output.to_vec(); inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]); sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); @@ -82,7 +82,7 @@ fn fn_sig_for_fn_abi<'tcx>( // a separate def-id for these bodies. let mut coroutine_kind = args.as_coroutine_closure().kind(); - let env_ty = if let InstanceKind::Shim(ShimKind::ConstructCoroutineInClosureShim { + let env_ty = if let InstanceKind::Shim(ShimKind::ConstructCoroutineInClosure { receiver_by_ref, .. }) = instance.def @@ -266,7 +266,7 @@ impl<'tcx> FnAbiDesc<'tcx> { let ty::PseudoCanonicalInput { typing_env, value: (instance, extra_args) } = query; let is_virtual_call = matches!(instance.def, ty::InstanceKind::Virtual(..)); let is_tls_shim_call = - matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::ThreadLocalShim(_))); + matches!(instance.def, ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(_))); Self { layout_cx: LayoutCx::new(tcx, typing_env), sig: tcx.normalize_erasing_regions( diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 25edafce89f13..34a3a96f89c40 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -83,10 +83,10 @@ fn resolve_instance_raw<'tcx>( _ => return Ok(None), } debug!(" => nontrivial async drop glue ctor"); - ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(def_id, ty)) + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(def_id, ty)) } else { debug!(" => trivial async drop glue ctor"); - ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtorShim(def_id, ty)) + ty::InstanceKind::Shim(ty::ShimKind::AsyncDropGlueCtor(def_id, ty)) } } else if tcx.is_async_drop_in_place_coroutine(def_id) { let ty = args.type_at(0); @@ -280,10 +280,7 @@ fn resolve_associated_item<'tcx>( }; Some(Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::CloneShim( - trait_item_id, - self_ty, - )), + def: ty::InstanceKind::Shim(ty::ShimKind::Clone(trait_item_id, self_ty)), args: rcvr_args, }) } else { @@ -300,7 +297,7 @@ fn resolve_associated_item<'tcx>( return Ok(None); } Some(Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddrShim( + def: ty::InstanceKind::Shim(ty::ShimKind::FnPtrAddr( trait_item_id, self_ty, )), @@ -333,7 +330,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim( + def: ty::InstanceKind::Shim(ty::ShimKind::FnPtr( trait_item_id, rcvr_args.type_at(0), )), @@ -350,7 +347,7 @@ fn resolve_associated_item<'tcx>( } else { Some(Instance { def: ty::InstanceKind::Shim( - ty::ShimKind::ConstructCoroutineInClosureShim { + ty::ShimKind::ConstructCoroutineInClosure { coroutine_closure_def_id, receiver_by_ref: target_kind != ty::ClosureKind::FnOnce, }, @@ -375,7 +372,7 @@ fn resolve_associated_item<'tcx>( // construct a new body that has the right return types. Some(Instance { def: ty::InstanceKind::Shim( - ty::ShimKind::ConstructCoroutineInClosureShim { + ty::ShimKind::ConstructCoroutineInClosure { coroutine_closure_def_id, receiver_by_ref: false, }, @@ -390,7 +387,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceKind::Shim(ty::ShimKind::FnPtrShim( + def: ty::InstanceKind::Shim(ty::ShimKind::FnPtr( trait_item_id, rcvr_args.type_at(0), )), From d06469a60bcee336a64499d0f799cb8f02903643 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 18 Jun 2026 22:43:45 +0000 Subject: [PATCH 099/116] Remove `MirSource::from_instance` helper that is only used in one place It used to be much more prevalent before I extracted shims as their own enum. --- compiler/rustc_middle/src/mir/mod.rs | 4 ---- compiler/rustc_mir_transform/src/coroutine/by_move_body.rs | 6 ++++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 23e6fc15c2ede..3facba24d3fd7 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -127,10 +127,6 @@ impl<'tcx> MirSource<'tcx> { MirSource { instance: InstanceKind::Item(def_id), promoted: None } } - pub fn from_instance(instance: InstanceKind<'tcx>) -> Self { - MirSource { instance, promoted: None } - } - pub fn from_shim(shim: ShimKind<'tcx>) -> Self { MirSource { instance: InstanceKind::Shim(shim), promoted: None } } diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 411f090e34921..5933892ecd886 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -223,8 +223,10 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( None, &mut PerParentDisambiguatorState::new(parent_def_id), ); - by_move_body.source = - mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); + by_move_body.source = mir::MirSource { + instance: InstanceKind::Item(body_def.def_id().to_def_id()), + promoted: None, + }; if let Some(dumper) = MirDumper::new(tcx, "built", &by_move_body) { dumper.set_disambiguator(&"after").dump_mir(&by_move_body); From 7d42183eeb7f5d9b46a7a7caa79f8a8fe8073c07 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Mon, 22 Jun 2026 23:58:33 +0300 Subject: [PATCH 100/116] Add support for infers in delegation's generics --- compiler/rustc_ast_lowering/src/delegation.rs | 97 +- .../src/delegation/generics.rs | 498 ++++--- .../rustc_ast_lowering/src/diagnostics.rs | 9 + compiler/rustc_ast_lowering/src/lib.rs | 3 + compiler/rustc_hir/src/hir.rs | 28 +- compiler/rustc_hir_analysis/src/delegation.rs | 240 ++- .../rustc_hir_analysis/src/diagnostics.rs | 8 - .../src/hir_ty_lowering/generics.rs | 44 +- tests/pretty/delegation-self-rename.pp | 13 +- .../generics/free-fn-to-trait-infer.rs | 19 - .../generics/free-fn-to-trait-infer.stderr | 27 - .../generics/free-to-trait-static-reuse.rs | 8 - .../free-to-trait-static-reuse.stderr | 107 +- .../generics/generics-gen-args-errors.rs | 13 +- .../generics/generics-gen-args-errors.stderr | 210 ++- tests/ui/delegation/generics/infers.rs | 356 +++++ tests/ui/delegation/generics/infers.stderr | 1296 +++++++++++++++++ .../generics/trait-impl-wrong-args-count.rs | 5 + .../trait-impl-wrong-args-count.stderr | 122 +- .../unelided-lifetime-in-sig-ice-156848.rs | 6 +- ...unelided-lifetime-in-sig-ice-156848.stderr | 27 - tests/ui/delegation/self-ty-ice-156388.rs | 3 +- tests/ui/delegation/self-ty-ice-156388.stderr | 10 +- tests/ui/delegation/target-expr.rs | 1 - tests/ui/delegation/target-expr.stderr | 21 +- .../ui/delegation/unsupported.current.stderr | 10 +- tests/ui/delegation/unsupported.next.stderr | 10 +- tests/ui/delegation/unsupported.rs | 1 - 28 files changed, 2416 insertions(+), 776 deletions(-) delete mode 100644 tests/ui/delegation/generics/free-fn-to-trait-infer.rs delete mode 100644 tests/ui/delegation/generics/free-fn-to-trait-infer.stderr create mode 100644 tests/ui/delegation/generics/infers.rs create mode 100644 tests/ui/delegation/generics/infers.stderr delete mode 100644 tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 3ead3b86cb591..fc466246bf137 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -194,7 +194,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return self.generate_delegation_error(span, delegation); } - let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method); + let mut generics = self.uplift_delegation_generics(delegation, sig_id); let (body_id, call_expr_id, unused_target_expr) = self.lower_delegation_body( delegation, @@ -404,10 +404,10 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationInfo { call_expr_id, call_path_res: self.get_resolution_id(call_path_node_id), - child_args_segment_id: generics.child.args_segment_id, - parent_args_segment_id: generics.parent.args_segment_id, - self_ty_id: generics.self_ty_id, - propagate_self_ty: generics.propagate_self_ty, + child_seg_id: generics.child.args_segment_id, + child_seg_id_for_sig: generics.child.segment_id_for_sig(), + parent_seg_id_for_sig: generics.parent.segment_id_for_sig(), + self_ty_propagation_kind: generics.self_ty_propagation_kind, group_id: { let id = match source { DelegationSource::Single => None, @@ -625,20 +625,40 @@ impl<'hir> LoweringContext<'_, 'hir> { }), ); - hir::QPath::Resolved(ty, self.arena.alloc(new_path)) - } - hir::QPath::TypeRelative(ty, segment) => { - let segment = self.process_segment(span, segment, &mut generics.child); + // Explicitly create `Self` self-type in case of infers or static + // free-to-trait reuses. + let ty = match generics.self_ty_propagation_kind { + Some(hir::DelegationSelfTyPropagationKind::SelfParam) => { + let self_param = generics.parent.generics.find_self_param(); + let path = self.create_generic_arg_path(self_param); + let kind = hir::TyKind::Path(path); + + let ty = match ty { + Some(ty) => hir::Ty { kind, ..ty.clone() }, + None => hir::Ty { kind, hir_id: self.next_id(), span }, + }; + + Some(&*self.arena.alloc(ty)) + } + _ => ty, + }; - hir::QPath::TypeRelative(ty, self.arena.alloc(segment)) + hir::QPath::Resolved(ty, self.arena.alloc(new_path)) } + hir::QPath::TypeRelative(..) => unreachable!("until inherent methods are supported"), }; - generics.self_ty_id = match new_path { - hir::QPath::Resolved(ty, _) => ty, - hir::QPath::TypeRelative(ty, _) => Some(ty), + if let Some(hir::DelegationSelfTyPropagationKind::SelfTy(id)) = + generics.self_ty_propagation_kind.as_mut() + { + *id = match new_path { + hir::QPath::Resolved(ty, _) => { + ty.expect("must contain self type as `SelfTy` propagation kind is specified") + } + hir::QPath::TypeRelative(ty, _) => ty, + } + .hir_id; } - .map(|ty| ty.hir_id); let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span)); let args = self.arena.alloc_from_iter(args); @@ -662,25 +682,38 @@ impl<'hir> LoweringContext<'_, 'hir> { segment: &hir::PathSegment<'hir>, result: &mut GenericsGenerationResult<'hir>, ) -> hir::PathSegment<'hir> { - let details = result.generics.args_propagation_details(); - - // Always uplift generic params, because if they are not empty then they - // should be generated in delegation. - let generics = result.generics.into_hir_generics(self, span); - let segment = if details.should_propagate { - let args = generics.into_generic_args(self, span); - - // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). - let args = if args.is_empty() { None } else { Some(args) }; - - hir::PathSegment { args, ..segment.clone() } - } else { - segment.clone() - }; + let infer_indices = result.generics.infer_indices(); + result.generics.into_hir_generics(self, span); + + let mut segment = segment.clone(); + let mut args_iter = result.generics.create_args_iterator(); + + let new_args = segment + .args + .filter(|args| !args.is_empty()) + .map(|args| { + self.arena.alloc_from_iter(args.args.iter().enumerate().map(|(idx, arg)| { + if infer_indices.contains(&idx) { + args_iter.next(self, |_| arg.hir_id()).expect("arg must exist for infer") + } else { + *arg + } + })) + }) + .unwrap_or_else(|| self.arena.alloc_from_iter(args_iter.consume_all(self))); + + // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). + segment.args = (!new_args.is_empty()).then(|| { + &*self.arena.alloc(hir::GenericArgs { + args: new_args, + constraints: &[], + parenthesized: hir::GenericArgsParentheses::No, + span_ext: segment.args.map_or(span, |args| args.span_ext), + }) + }); - if details.use_args_in_sig_inheritance { - result.args_segment_id = Some(segment.hir_id); - } + result.args_segment_id = segment.hir_id; + result.use_for_sig_inheritance = !result.generics.is_trait_impl(); segment } diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index f8e3528750035..79a3961c22a53 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -1,6 +1,7 @@ use hir::HirId; use hir::def::{DefKind, Res}; use rustc_ast::*; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericParamDefKind; @@ -9,21 +10,7 @@ use rustc_span::symbol::kw; use rustc_span::{Ident, Span, sym}; use crate::LoweringContext; - -#[derive(Clone, Copy)] -pub(super) enum DelegationGenericsKind { - /// User-specified args are present: `reuse foo::;`. - UserSpecified, - /// The default case when no user-specified args are present: `reuse Trait::foo;`. - Default, - /// In free-to-trait reuse, when user specified args for trait `reuse Trait::::foo;` - /// in this case we need to both generate `Self` and process user args. - SelfAndUserSpecified, - /// In delegations from trait impl to other entities like free functions or trait functions, - /// we want to generate a function whose generics matches generics of signature function - /// in trait. - TraitImpl(bool /* Has user-specified args */), -} +use crate::diagnostics::DelegationInfersMismatch; #[derive(Debug, Clone, Copy)] pub(super) enum GenericsPosition { @@ -31,30 +18,30 @@ pub(super) enum GenericsPosition { Child, } +#[derive(Debug)] +pub(super) enum GenericArgSlot { + UserSpecified, + Generate(T, Option /* Infer arg index from AST */), +} + pub(super) struct DelegationGenerics { - generics: T, - kind: DelegationGenericsKind, + data: T, pos: GenericsPosition, + trait_impl: bool, } -impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> { - fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { - DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default } - } - - fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { - DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified } - } +type TyGenerics<'hir> = Vec>; - fn trait_impl( - generics: &'hir [ty::GenericParamDef], - user_specified: bool, +impl<'hir> DelegationGenerics> { + fn generate_all( + params: &'hir [ty::GenericParamDef], pos: GenericsPosition, + trait_impl: bool, ) -> Self { DelegationGenerics { - generics, + data: params.iter().map(|p| GenericArgSlot::Generate(p, None)).collect(), pos, - kind: DelegationGenericsKind::TraitImpl(user_specified), + trait_impl, } } } @@ -70,103 +57,176 @@ impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> { /// (i.e., method call scenarios), in such a case this approach helps /// a lot as if `into_hir_generics` will not be called then uplifting will not happen. pub(super) enum HirOrTyGenerics<'hir> { - Ty(DelegationGenerics<&'hir [ty::GenericParamDef]>), + Ty(DelegationGenerics>), Hir(DelegationGenerics<&'hir hir::Generics<'hir>>), } pub(super) struct GenericsGenerationResult<'hir> { pub(super) generics: HirOrTyGenerics<'hir>, - pub(super) args_segment_id: Option, + pub(super) args_segment_id: HirId, + pub(super) use_for_sig_inheritance: bool, +} + +impl GenericsGenerationResult<'_> { + pub(super) fn segment_id_for_sig(&self) -> Option { + self.use_for_sig_inheritance.then(|| self.args_segment_id) + } } pub(super) struct GenericsGenerationResults<'hir> { pub(super) parent: GenericsGenerationResult<'hir>, pub(super) child: GenericsGenerationResult<'hir>, - pub(super) self_ty_id: Option, - pub(super) propagate_self_ty: bool, + pub(super) self_ty_propagation_kind: Option, } -pub(super) struct GenericArgsPropagationDetails { - pub(super) should_propagate: bool, - pub(super) use_args_in_sig_inheritance: bool, +pub(super) struct DelegationGenericArgsIterator<'hir> { + index: usize = Default::default(), + params: &'hir [hir::GenericParam<'hir>], } -impl DelegationGenericsKind { - fn args_propagation_details(self) -> GenericArgsPropagationDetails { - match self { - DelegationGenericsKind::UserSpecified - | DelegationGenericsKind::SelfAndUserSpecified => GenericArgsPropagationDetails { - should_propagate: false, - use_args_in_sig_inheritance: true, - }, - DelegationGenericsKind::TraitImpl(user_specified) => GenericArgsPropagationDetails { - should_propagate: !user_specified, - use_args_in_sig_inheritance: false, - }, - DelegationGenericsKind::Default => GenericArgsPropagationDetails { - should_propagate: true, - use_args_in_sig_inheritance: false, - }, +/// During generic args propagation we need to create generic args +/// (and their `HirId`s) on demand, as some of generic args can not be used +/// and in this case an assert of an unseen `HirId` will be triggered. Moreover, +/// when replacing infers with generated generic params we should reuse existing +/// `HirId` of replaced infer, thus this iterator abstracts the way `HirId`s are +/// created for new generic args. +impl<'hir> DelegationGenericArgsIterator<'hir> { + pub(super) fn next( + &mut self, + ctx: &mut LoweringContext<'_, 'hir>, + hir_id_factory: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> HirId, + ) -> Option> { + let p = loop { + if self.index >= self.params.len() { + return None; + } + + let p = self.params[self.index]; + self.index += 1; + + // Skip self generic arg, we do not need to propagate it. + if p.name.ident().name == kw::SelfUpper || p.is_impl_trait() { + continue; + } + + break p; + }; + + let hir_id = hir_id_factory(ctx); + + Some(match p.kind { + hir::GenericParamKind::Lifetime { .. } => { + hir::GenericArg::Lifetime(ctx.arena.alloc(hir::Lifetime { + hir_id, + ident: p.name.ident(), + kind: hir::LifetimeKind::Param(p.def_id), + source: hir::LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full }, + syntax: hir::LifetimeSyntax::ExplicitBound, + })) + } + hir::GenericParamKind::Type { .. } => hir::GenericArg::Type(ctx.arena.alloc(hir::Ty { + hir_id, + span: p.span, + kind: hir::TyKind::Path(ctx.create_generic_arg_path(&p)), + })), + hir::GenericParamKind::Const { .. } => { + hir::GenericArg::Const(ctx.arena.alloc(hir::ConstArg { + hir_id, + kind: hir::ConstArgKind::Path(ctx.create_generic_arg_path(&p)), + span: p.span, + })) + } + }) + } + + pub(super) fn consume_all( + mut self, + ctx: &mut LoweringContext<'_, 'hir>, + ) -> Vec> { + let mut args = vec![]; + while let Some(arg) = self.next(ctx, |ctx| ctx.next_id()) { + args.push(arg); } + + args } } impl<'hir> HirOrTyGenerics<'hir> { - pub(super) fn into_hir_generics( - &mut self, - ctx: &mut LoweringContext<'_, 'hir>, - span: Span, - ) -> &mut HirOrTyGenerics<'hir> { + pub(super) fn into_hir_generics(&mut self, ctx: &mut LoweringContext<'_, 'hir>, span: Span) { if let HirOrTyGenerics::Ty(ty) = self { let rename_self = matches!(ty.pos, GenericsPosition::Child); - let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self); + let params = ctx.uplift_delegation_generic_params(span, &ty.data, rename_self); *self = HirOrTyGenerics::Hir(DelegationGenerics { - generics: params, - kind: ty.kind, + data: params, pos: ty.pos, + trait_impl: ty.trait_impl, }); } - - self } fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> { match self { HirOrTyGenerics::Ty(_) => hir::Generics::empty(), - HirOrTyGenerics::Hir(hir) => hir.generics, + HirOrTyGenerics::Hir(hir) => hir.data, } } - pub(super) fn into_generic_args( - &self, - ctx: &mut LoweringContext<'_, 'hir>, - span: Span, - ) -> &'hir hir::GenericArgs<'hir> { + pub(super) fn create_args_iterator(&self) -> DelegationGenericArgsIterator<'hir> { match self { HirOrTyGenerics::Ty(_) => { - bug!("Attempting to get generic args before uplifting to HIR") + bug!("attempting to get generic args before uplifting to HIR") } HirOrTyGenerics::Hir(hir) => { - let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent); - ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span) + DelegationGenericArgsIterator { params: hir.data.params, .. } } } } - pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails { + pub(super) fn infer_indices(&self) -> FxHashSet { match self { - HirOrTyGenerics::Ty(ty) => ty.kind.args_propagation_details(), - HirOrTyGenerics::Hir(hir) => hir.kind.args_propagation_details(), + HirOrTyGenerics::Ty(ty) => ty + .data + .iter() + .flat_map(|slot| match slot { + GenericArgSlot::Generate(_, Some(idx)) => Some(*idx), + _ => None, + }) + .collect(), + HirOrTyGenerics::Hir(_) => bug!("accessed infer indices on uplifted generics"), + } + } + + pub(super) fn is_trait_impl(&self) -> bool { + match self { + HirOrTyGenerics::Ty(ty) => ty.trait_impl, + HirOrTyGenerics::Hir(hir) => hir.trait_impl, + } + } + + pub(super) fn find_self_param(&self) -> &'hir hir::GenericParam<'hir> { + match self { + HirOrTyGenerics::Ty(_) => { + bug!("accessed ty-level generics while searching for uplifted `Self` param") + } + HirOrTyGenerics::Hir(hir) => hir + .data + .params + .iter() + .find(|p| p.name.ident().name == kw::SelfUpper) + .expect("`Self` generic param is not found while expected"), } } } impl<'hir> GenericsGenerationResult<'hir> { - fn new( - generics: DelegationGenerics<&'hir [ty::GenericParamDef]>, - ) -> GenericsGenerationResult<'hir> { - GenericsGenerationResult { generics: HirOrTyGenerics::Ty(generics), args_segment_id: None } + fn new(generics: DelegationGenerics>) -> GenericsGenerationResult<'hir> { + GenericsGenerationResult { + generics: HirOrTyGenerics::Ty(generics), + args_segment_id: HirId::INVALID, + use_for_sig_inheritance: false, + } } } @@ -208,13 +268,30 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, delegation: &Delegation, sig_id: DefId, - is_method: bool, ) -> GenericsGenerationResults<'hir> { let delegation_parent_kind = self.tcx.def_kind(self.tcx.local_parent(self.owner.def_id)); let segments = &delegation.path.segments; let len = segments.len(); - let child_user_specified = segments[len - 1].args.is_some(); + + let get_user_args = |idx: usize| -> Option<&AngleBracketedArgs> { + let segment = &segments[idx]; + + let Some(args) = segment.args.as_ref() else { return None }; + let GenericArgs::AngleBracketed(args) = args else { + self.tcx.dcx().span_delayed_bug( + segment.span(), + "expected angle-bracketed generic args in delegation segment", + ); + + return None; + }; + + // Treat empty args `reuse foo::<> as bar` as `reuse foo as bar`, + // the same logic applied when we call function `fn f(t: T)` + // like that `f::<>(())`, in HIR no `<>` will be generated. + (!args.args.is_empty()).then(|| args) + }; let sig_params = &self.tcx.generics_of(sig_id).own_params[..]; @@ -223,23 +300,15 @@ impl<'hir> LoweringContext<'_, 'hir> { if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) { // Considering parent generics, during signature inheritance // we will take those args that are in trait impl header trait ref. - let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent); - let parent = GenericsGenerationResult::new(parent); + let parent = + DelegationGenerics { data: vec![], pos: GenericsPosition::Child, trait_impl: true }; - let child = DelegationGenerics::trait_impl( - sig_params, - child_user_specified, - GenericsPosition::Child, - ); + let parent = GenericsGenerationResult::new(parent); + let child = DelegationGenerics::generate_all(sig_params, GenericsPosition::Child, true); let child = GenericsGenerationResult::new(child); - return GenericsGenerationResults { - parent, - child, - self_ty_id: None, - propagate_self_ty: false, - }; + return GenericsGenerationResults { parent, child, self_ty_propagation_kind: None }; } let delegation_in_free_ctx = @@ -248,7 +317,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let sig_parent = self.tcx.parent(sig_id); let sig_in_trait = matches!(self.tcx.def_kind(sig_parent), DefKind::Trait); let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait; - let generate_self = free_to_trait_delegation && is_method && delegation.qself.is_none(); + + let qself_is_infer = + delegation.qself.as_ref().is_some_and(|qself| qself.ty.is_maybe_parenthesised_infer()); + + let qself_is_none = delegation.qself.is_none(); + + let generate_self = free_to_trait_delegation && (qself_is_none || qself_is_infer); let can_add_generics_to_parent = len >= 2 && self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| { @@ -256,57 +331,137 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let parent_generics = if can_add_generics_to_parent { - let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..]; - - if segments[len - 2].args.is_some() { - if generate_self { - // Take only first Self parameter, it is trait so Self must be present. - DelegationGenerics { - kind: DelegationGenericsKind::SelfAndUserSpecified, - generics: &sig_parent_params[..1], - pos: GenericsPosition::Parent, - } - } else { - DelegationGenerics::user_specified(&[], GenericsPosition::Parent) + let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params; + + if let Some(args) = get_user_args(len - 2) { + DelegationGenerics { + data: self.create_slots_from_args( + args, + &sig_parent_params[usize::from(!generate_self)..], + generate_self, + ), + pos: GenericsPosition::Parent, + trait_impl: false, } } else { - let skip_self = usize::from(!generate_self); - DelegationGenerics::default( - &sig_parent_params[skip_self..], + DelegationGenerics::generate_all( + &sig_parent_params[usize::from(!generate_self)..], GenericsPosition::Parent, + false, ) } } else { - DelegationGenerics::default(&[], GenericsPosition::Parent) + DelegationGenerics { data: vec![], pos: GenericsPosition::Parent, trait_impl: false } }; - let child_generics = if child_user_specified { + let child_generics = if let Some(args) = get_user_args(len - 1) { let synth_params_index = sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len()); - DelegationGenerics::user_specified( - &sig_params[synth_params_index..], - GenericsPosition::Child, - ) + let mut slots = + self.create_slots_from_args(args, &sig_params[..synth_params_index], false); + + for synth_param in &sig_params[synth_params_index..] { + slots.push(GenericArgSlot::Generate(synth_param, None)); + } + + DelegationGenerics { data: slots, pos: GenericsPosition::Child, trait_impl: false } } else { - DelegationGenerics::default(sig_params, GenericsPosition::Child) + DelegationGenerics::generate_all(sig_params, GenericsPosition::Child, false) }; GenericsGenerationResults { parent: GenericsGenerationResult::new(parent_generics), child: GenericsGenerationResult::new(child_generics), - self_ty_id: None, - propagate_self_ty: free_to_trait_delegation && !generate_self, + self_ty_propagation_kind: match free_to_trait_delegation { + true => Some(match qself_is_none { + true => hir::DelegationSelfTyPropagationKind::SelfParam, + false => match qself_is_infer { + true => hir::DelegationSelfTyPropagationKind::SelfParam, + // HirId is filled during generic args propagation. + false => hir::DelegationSelfTyPropagationKind::SelfTy(HirId::INVALID), + }, + }), + false => None, + }, + } + } + + /// Generates generic argument slots for user-specified `args` and + /// generic `params` of the signature function. This function checks whether + /// there are infers (`kw::UnderscoreLifetime` or `kw::Underscore`) in + /// user-specified args, and if so we add `Generate` slot meaning we have to + /// generate generic param for delegation and propagate it instead of this infer. + /// We zip over user-specified args and signature generic params, so if there are more + /// infers than generic params then we will not process all infers thus not generating + /// more generic params then needed (anyway it is an error). + fn create_slots_from_args( + &self, + args: &AngleBracketedArgs, + params: &'hir [ty::GenericParamDef], + add_first_self: bool, + ) -> TyGenerics<'hir> { + let mut slots = vec![]; + if add_first_self { + slots.push(GenericArgSlot::Generate(¶ms[0], None)); + } + + let params = ¶ms[usize::from(add_first_self)..]; + for (idx, (arg, param)) in args.args.iter().zip(params).enumerate() { + let AngleBracketedArg::Arg(arg) = arg else { continue }; + + let is_infer = match arg { + GenericArg::Lifetime(lt) => lt.ident.name == kw::UnderscoreLifetime, + GenericArg::Type(ty) => ty.is_maybe_parenthesised_infer(), + GenericArg::Const(_) => false, + }; + + // If `'_` is used instead of `_` (or vice versa) we emit a meaningful + // error instead of processing this infer or leaving it as is for signature + // inheritance. + if is_infer + && matches!( + (arg, ¶m.kind), + ( + GenericArg::Lifetime(_), + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } + ) | ( + GenericArg::Type(_) | GenericArg::Const(_), + GenericParamDefKind::Lifetime { .. } + ) + ) + { + let (actual, expected) = if matches!(arg, GenericArg::Lifetime(..)) { + (kw::UnderscoreLifetime, kw::Underscore) + } else { + (kw::Underscore, kw::UnderscoreLifetime) + }; + + self.tcx.dcx().emit_err(DelegationInfersMismatch { + span: arg.span(), + actual, + expected, + }); + } + + slots.push(match is_infer { + true => GenericArgSlot::Generate(param, Some(idx)), + false => GenericArgSlot::UserSpecified, + }); } + + slots } fn uplift_delegation_generic_params( &mut self, span: Span, - params: &'hir [ty::GenericParamDef], + params: &[GenericArgSlot<&ty::GenericParamDef>], rename_self: bool, ) -> &'hir hir::Generics<'hir> { - let params = self.arena.alloc_from_iter(params.iter().map(|p| { + let params = self.arena.alloc_from_iter(params.iter().flat_map(|p| { + let GenericArgSlot::Generate(p, _) = p else { return None }; + let def_kind = match p.kind { GenericParamDefKind::Lifetime => DefKind::LifetimeParam, GenericParamDefKind::Type { .. } => DefKind::TyParam, @@ -354,7 +509,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `lower_node_id` routine so param's id is added to `self.children`. let hir_id = self.lower_node_id(node_id); - hir::GenericParam { + Some(hir::GenericParam { hir_id, colon_span: Some(span), def_id, @@ -363,7 +518,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pure_wrt_drop: p.pure_wrt_drop, source: hir::GenericParamSource::Generics, span, - } + }) })); // HACK: for now we generate predicates such that all lifetimes are early bound, @@ -413,77 +568,32 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn create_generics_args_from_params( + pub(super) fn create_generic_arg_path( &mut self, - params: &[hir::GenericParam<'hir>], - add_lifetimes: bool, - span: Span, - ) -> &'hir hir::GenericArgs<'hir> { - self.arena.alloc(hir::GenericArgs { - args: self.arena.alloc_from_iter(params.iter().filter_map(|p| { - // Skip self generic arg, we do not need to propagate it. - if p.name.ident().name == kw::SelfUpper || p.is_impl_trait() { - return None; - } - - let create_path = |this: &mut Self| { - let res = Res::Def( - match p.kind { - hir::GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam, - hir::GenericParamKind::Type { .. } => DefKind::TyParam, - hir::GenericParamKind::Const { .. } => DefKind::ConstParam, - }, - p.def_id.to_def_id(), - ); - - hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - segments: this.arena.alloc_slice(&[hir::PathSegment { - args: None, - hir_id: this.next_id(), - ident: p.name.ident(), - infer_args: false, - res, - }]), - res, - span: p.span, - }), - ) - }; - - match p.kind { - hir::GenericParamKind::Lifetime { .. } => match add_lifetimes { - true => Some(hir::GenericArg::Lifetime(self.arena.alloc(hir::Lifetime { - hir_id: self.next_id(), - ident: p.name.ident(), - kind: hir::LifetimeKind::Param(p.def_id), - source: hir::LifetimeSource::Path { - angle_brackets: hir::AngleBrackets::Full, - }, - syntax: hir::LifetimeSyntax::ExplicitBound, - }))), - false => None, - }, - hir::GenericParamKind::Type { .. } => { - Some(hir::GenericArg::Type(self.arena.alloc(hir::Ty { - hir_id: self.next_id(), - span: p.span, - kind: hir::TyKind::Path(create_path(self)), - }))) - } - hir::GenericParamKind::Const { .. } => { - Some(hir::GenericArg::Const(self.arena.alloc(hir::ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Path(create_path(self)), - span: p.span, - }))) - } - } - })), - constraints: &[], - parenthesized: hir::GenericArgsParentheses::No, - span_ext: span, - }) + p: &hir::GenericParam<'hir>, + ) -> hir::QPath<'hir> { + let res = Res::Def( + match p.kind { + hir::GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam, + hir::GenericParamKind::Type { .. } => DefKind::TyParam, + hir::GenericParamKind::Const { .. } => DefKind::ConstParam, + }, + p.def_id.to_def_id(), + ); + + hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + segments: self.arena.alloc_slice(&[hir::PathSegment { + args: None, + hir_id: self.next_id(), + ident: p.name.ident(), + infer_args: false, + res, + }]), + res, + span: p.span, + }), + ) } } diff --git a/compiler/rustc_ast_lowering/src/diagnostics.rs b/compiler/rustc_ast_lowering/src/diagnostics.rs index 31f094209a946..238a16d9b859d 100644 --- a/compiler/rustc_ast_lowering/src/diagnostics.rs +++ b/compiler/rustc_ast_lowering/src/diagnostics.rs @@ -560,3 +560,12 @@ pub(crate) struct DelegationAttemptedBlockWithDefsDeletion { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag("wrong infer used: expected {$expected}, found: {$actual}")] +pub(crate) struct DelegationInfersMismatch { + #[primary_span] + pub span: Span, + pub expected: Symbol, + pub actual: Symbol, +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b8d708d42ff10..06e83a7486100 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -31,6 +31,9 @@ //! in the HIR, especially for multiple identifiers. // tidy-alphabetical-start +#![feature(const_default)] +#![feature(const_trait_impl)] +#![feature(default_field_values)] #![feature(deref_patterns)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8d886e7ac6fbf..cd7a9a6cd721c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3854,14 +3854,34 @@ pub enum OpaqueTyOrigin { }, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, StableHash)] +pub enum DelegationSelfTyPropagationKind { + /// Used when self type is explicitly specified in free-to-trait reuse + /// `reuse <() as Trait>::foo;`. + SelfTy(HirId /* Self ty id */), + /// Used when infer instead of a self type is specified or self type + /// is not specified at all: `reuse Trait::foo; reuse <_ as Trait>::foo;`. + SelfParam, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, StableHash)] pub struct DelegationInfo { pub call_expr_id: HirId, pub call_path_res: Option, - pub parent_args_segment_id: Option, - pub child_args_segment_id: Option, - pub self_ty_id: Option, - pub propagate_self_ty: bool, + + /// Id of the child segment in delegation: `reuse Trait::foo`, + /// `child_seg_id` points to `foo`. + pub child_seg_id: HirId, + + /// Ids of parent and child segments, `Some` when we need to take + /// generic args of those segments for signature/predicates inheritance. + /// `None` in trait impl case or when error delegation is generated, meaning + /// we should not access those segments for generic args lowering. + /// When `child_seg_id_for_sig` is Some it always equals `child_seg_id`. + pub parent_seg_id_for_sig: Option, + pub child_seg_id_for_sig: Option, + + pub self_ty_propagation_kind: Option, pub group_id: Option<(LocalExpnId, bool /* unused_target_expr */)>, } diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 7f3edd7f09231..de2315edb7e8f 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -5,16 +5,15 @@ use std::debug_assert_matches; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::PathSegment; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{DelegationSelfTyPropagationKind, PathSegment}; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_span::{ErrorGuaranteed, Span, kw}; use crate::collect::ItemCtxt; -use crate::diagnostics::DelegationSelfTypeNotSpecified; use crate::hir_ty_lowering::HirTyLowerer; type RemapTable = FxHashMap; @@ -65,8 +64,9 @@ impl<'tcx> TypeFolder> for ParamIndexRemapper<'tcx> { } } +#[derive(Debug)] enum SelfPositionKind { - AfterLifetimes(bool /* Should propagate self ty */), + AfterLifetimes(Option), Zero, None, } @@ -83,8 +83,8 @@ fn create_self_position_kind( | (FnKind::AssocTrait, FnKind::Free) => SelfPositionKind::Zero, (FnKind::Free, FnKind::AssocTrait) => { - let propagate_self_ty = tcx.hir_delegation_info(delegation_id).propagate_self_ty; - SelfPositionKind::AfterLifetimes(propagate_self_ty) + let kind = tcx.hir_delegation_info(delegation_id).self_ty_propagation_kind; + SelfPositionKind::AfterLifetimes(kind) } _ => SelfPositionKind::None, @@ -268,28 +268,6 @@ fn get_parent_and_inheritance_kind<'tcx>( } } -fn get_delegation_self_ty_or_err(tcx: TyCtxt<'_>, delegation_id: LocalDefId) -> Ty<'_> { - tcx.hir_delegation_info(delegation_id) - .self_ty_id - .map(|id| { - let ctx = ItemCtxt::new(tcx, delegation_id); - ctx.lower_ty(tcx.hir_node(id).expect_ty()) - }) - .unwrap_or_else(|| { - // It is possible to attempt to get self type when it is used in signature - // (i.e., `fn default() -> Self`), so emit error here in addition to possible - // `mismatched types` error (see #156388). - let err = DelegationSelfTypeNotSpecified { span: tcx.def_span(delegation_id) }; - tcx.dcx().emit_err(err); - - Ty::new_error_with_message( - tcx, - tcx.def_span(delegation_id), - "the self type must be specified", - ) - }) -} - fn get_delegation_self_ty<'tcx>(tcx: TyCtxt<'tcx>, delegation_id: LocalDefId) -> Option> { let sig_id = tcx.hir_opt_delegation_sig_id(delegation_id).expect("Delegation must have sig_id"); let (caller_kind, callee_kind) = (fn_kind(tcx, delegation_id), fn_kind(tcx, sig_id)); @@ -302,14 +280,24 @@ fn get_delegation_self_ty<'tcx>(tcx: TyCtxt<'tcx>, delegation_id: LocalDefId) -> | (FnKind::AssocTrait, FnKind::AssocTrait) => { match create_self_position_kind(tcx, delegation_id, sig_id) { SelfPositionKind::None => None, - SelfPositionKind::AfterLifetimes(propagate_self_ty) => { - if propagate_self_ty { - Some(get_delegation_self_ty_or_err(tcx, delegation_id)) - } else { - // Both sig parent and child lifetimes are in included in this count. - let index = tcx.generics_of(delegation_id).own_counts().lifetimes; - Some(Ty::new_param(tcx, index as u32, kw::SelfUpper)) - } + SelfPositionKind::AfterLifetimes(propagation_kind) => { + Some(match propagation_kind { + Some(kind) => match kind { + DelegationSelfTyPropagationKind::SelfTy(self_ty_id) => { + let ctx = ItemCtxt::new(tcx, delegation_id); + ctx.lower_ty(tcx.hir_node(self_ty_id).expect_ty()) + } + DelegationSelfTyPropagationKind::SelfParam => { + let index = tcx.generics_of(delegation_id).own_counts().lifetimes; + Ty::new_param(tcx, index as u32, kw::SelfUpper) + } + }, + None => Ty::new_error_with_message( + tcx, + tcx.def_span(delegation_id), + "self propagation kind must be specified for `AfterLifetimes` variant", + ), + }) } SelfPositionKind::Zero => Some(Ty::new_param(tcx, 0, kw::SelfUpper)), } @@ -348,137 +336,69 @@ fn create_generic_args<'tcx>( sig_id: DefId, delegation_id: LocalDefId, mut parent_args: &[ty::GenericArg<'tcx>], - child_args: &[ty::GenericArg<'tcx>], + mut child_args: &[ty::GenericArg<'tcx>], ) -> Vec> { - let (caller_kind, callee_kind) = (fn_kind(tcx, delegation_id), fn_kind(tcx, sig_id)); - + let delegation_generics = tcx.generics_of(delegation_id); let delegation_args = ty::GenericArgs::identity_for_item(tcx, delegation_id); - let deleg_parent_args_without_self_count = - get_delegation_parent_args_count_without_self(tcx, delegation_id, sig_id); - - let delegation_generics = tcx.generics_of(delegation_id); let real_args_count = delegation_args.len() - delegation_generics.own_synthetic_params_count(); let synth_args = &delegation_args[real_args_count..]; - let delegation_args = &delegation_args[..real_args_count]; - - let args = match (caller_kind, callee_kind) { - (FnKind::Free, FnKind::Free) - | (FnKind::Free, FnKind::AssocTrait) - | (FnKind::AssocInherentImpl, FnKind::Free) - | (FnKind::AssocTrait, FnKind::Free) - | (FnKind::AssocTrait, FnKind::AssocTrait) => delegation_args, - (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { - // Special case, as user specifies Trait args in trait impl header, we want to treat - // them as parent args. We always generate a function whose generics match - // child generics in trait. - let parent = tcx.local_parent(delegation_id); - parent_args = - tcx.impl_trait_header(parent).trait_ref.instantiate_identity().skip_norm_wip().args; - - assert!(child_args.is_empty(), "Child args can not be used in trait impl case"); - - tcx.mk_args(&delegation_args[delegation_generics.parent_count..]) - } - - (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { - let self_ty = - tcx.type_of(tcx.local_parent(delegation_id)).instantiate_identity().skip_norm_wip(); + let mut delegation_parent_args = + &delegation_args[delegation_generics.has_self as usize..delegation_generics.parent_count]; - tcx.mk_args_from_iter( - std::iter::once(ty::GenericArg::from(self_ty)) - .chain(delegation_args.iter().copied()), - ) - } + let delegation_args = &delegation_args[delegation_generics.parent_count..]; - // For trait impl's `sig_id` is always equal to the corresponding trait method. - // For inherent methods delegation is not yet supported. - (FnKind::AssocTraitImpl, _) - | (_, FnKind::AssocTraitImpl) - | (_, FnKind::AssocInherentImpl) => unreachable!(), - }; + let kinds = (fn_kind(tcx, delegation_id), fn_kind(tcx, sig_id)); + if matches!(kinds, (FnKind::AssocTraitImpl, FnKind::AssocTrait)) { + // Special case, as user specifies Trait args in trait impl header, we want to treat + // them as parent args. We always generate a function whose generics match + // child generics in trait. + let parent = tcx.local_parent(delegation_id); - let mut new_args = vec![]; + parent_args = + tcx.impl_trait_header(parent).trait_ref.instantiate_identity().skip_norm_wip().args; - let self_pos_kind = create_self_position_kind(tcx, delegation_id, sig_id); - let mut lifetimes_end_pos; + child_args = + &delegation_args[delegation_args.len() - delegation_generics.own_params.len()..]; - if !parent_args.is_empty() { - let parent_args_lifetimes_count = - parent_args.iter().filter(|a| a.as_region().is_some()).count(); - - match self_pos_kind { - SelfPositionKind::AfterLifetimes { .. } => { - new_args.extend(&parent_args[1..1 + parent_args_lifetimes_count]); + delegation_parent_args = &[]; + } - lifetimes_end_pos = parent_args_lifetimes_count; + let self_type = get_delegation_self_ty(tcx, delegation_id).map(|t| t.into()); - new_args.push(parent_args[0]); + // Remove `Self` from parent args (it is always at the `0th` index) as it is + // added manually. + if self_type.is_some() && !parent_args.is_empty() { + parent_args = &parent_args[1..]; + } - new_args.extend(&parent_args[1 + parent_args_lifetimes_count..]); + let (zero_self, after_lifetimes_self) = + match create_self_position_kind(tcx, delegation_id, sig_id) { + SelfPositionKind::AfterLifetimes(_) => { + assert!(self_type.is_some()); + (None, self_type) } SelfPositionKind::Zero => { - lifetimes_end_pos = 1 /* Self */ + parent_args_lifetimes_count; - new_args.extend_from_slice(parent_args); - - for i in 0..deleg_parent_args_without_self_count { - new_args.insert(1 + i, args[1 + i]); - } - - lifetimes_end_pos += deleg_parent_args_without_self_count; + assert!(self_type.is_some()); + (self_type, None) } - // If we have parent args then we obtained them from trait, then self must be somewhere - SelfPositionKind::None => unreachable!(), + SelfPositionKind::None => (None, None), }; - } else { - let self_impact = matches!(self_pos_kind, SelfPositionKind::Zero) as usize; - - lifetimes_end_pos = self_impact - + deleg_parent_args_without_self_count - + &args[self_impact + deleg_parent_args_without_self_count..] - .iter() - .filter(|a| a.as_region().is_some()) - .count(); - - new_args.extend_from_slice(args); - - // Parent args are empty, then if we should propagate self ty (meaning Self generic - // param was not generated) then we should insert it, as it won't be in `args`. - if matches!(self_pos_kind, SelfPositionKind::AfterLifetimes(true)) { - new_args.insert( - lifetimes_end_pos, - ty::GenericArg::from(get_delegation_self_ty_or_err(tcx, delegation_id)), - ); - } - } - - if !child_args.is_empty() { - let child_lifetimes_count = child_args.iter().filter(|a| a.as_region().is_some()).count(); - - for i in 0..child_lifetimes_count { - new_args.insert(lifetimes_end_pos + i, child_args[i]); - } - new_args.extend_from_slice(&child_args[child_lifetimes_count..]); - } else if !parent_args.is_empty() { - let child_args = &delegation_args[delegation_generics.parent_count..]; - - let child_lifetimes_count = - child_args.iter().take_while(|a| a.as_region().is_some()).count(); - - for i in 0..child_lifetimes_count { - new_args.insert(lifetimes_end_pos + i, child_args[i]); - } - - // If self_ty is propagated it means that Self generic param was not generated. - let skip_self = matches!(self_pos_kind, SelfPositionKind::AfterLifetimes(false)); - new_args.extend(&child_args[child_lifetimes_count + skip_self as usize..]); - } - - new_args.extend(synth_args); - - new_args + let zero_self = zero_self.as_ref().into_iter(); + let after_lifetimes_self = after_lifetimes_self.as_ref().into_iter(); + + zero_self + .chain(delegation_parent_args) + .chain(parent_args.iter().filter(|a| a.as_region().is_some())) + .chain(child_args.iter().filter(|a| a.as_region().is_some())) + .chain(after_lifetimes_self) + .chain(parent_args.iter().filter(|a| a.as_region().is_none())) + .chain(child_args.iter().filter(|a| a.as_region().is_none())) + .chain(synth_args) + .copied() + .collect::>() } pub(crate) fn inherit_predicates_for_delegation_item<'tcx>( @@ -541,7 +461,10 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>( let (parent_args, child_args) = tcx.delegation_user_specified_args(def_id); let (folder, args) = create_folder_and_args(tcx, def_id, sig_id, parent_args, child_args); let self_pos_kind = create_self_position_kind(tcx, def_id, sig_id); - let filter_self_preds = matches!(self_pos_kind, SelfPositionKind::AfterLifetimes(true)); + let filter_self_preds = matches!( + self_pos_kind, + SelfPositionKind::AfterLifetimes(Some(DelegationSelfTyPropagationKind::SelfTy(..))) + ); let collector = PredicatesCollector { tcx, preds: vec![], args, folder, filter_self_preds }; let (parent, inh_kind) = get_parent_and_inheritance_kind(tcx, def_id, sig_id); @@ -640,18 +563,21 @@ pub(crate) fn delegation_user_specified_args<'tcx>( let ctx = ItemCtxt::new_for_delegation(tcx, delegation_id); let lowerer = ctx.lowerer(); + let parent_args = info + .parent_seg_id_for_sig + .and_then(get_segment) + .filter(|(_, def_id)| matches!(tcx.def_kind(*def_id), DefKind::Trait)) + .map(|(segment, def_id)| { + let self_ty = get_delegation_self_ty(tcx, delegation_id); - let parent_args = info.parent_args_segment_id.and_then(get_segment).map(|(segment, def_id)| { - let self_ty = get_delegation_self_ty(tcx, delegation_id); - - lowerer - .lower_generic_args_of_path(segment.ident.span, def_id, &[], segment, self_ty) - .0 - .as_slice() - }); + lowerer + .lower_generic_args_of_path(segment.ident.span, def_id, &[], segment, self_ty) + .0 + .as_slice() + }); let child_args = info - .child_args_segment_id + .child_seg_id_for_sig .and_then(get_segment) .filter(|(_, def_id)| matches!(tcx.def_kind(*def_id), DefKind::Fn | DefKind::AssocFn)) .map(|(segment, def_id)| { diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 5997f16b42917..1bfc495071284 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -1582,14 +1582,6 @@ pub(crate) struct UnsupportedDelegation<'a> { pub callee_span: Span, } -#[derive(Diagnostic)] -#[diag("delegation self type is not specified")] -#[help("consider explicitly specifying self type: `reuse ::function`")] -pub(crate) struct DelegationSelfTypeNotSpecified { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag("inferred lifetimes are not allowed in delegations as we need to inherit signature")] pub(crate) struct ElidedLifetimesAreNotAllowedInDelegations { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index a26d84291e42d..0187a22d564cb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -6,7 +6,7 @@ use rustc_errors::{ }; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, GenericArg}; +use rustc_hir::{self as hir, DelegationInfo, GenericArg}; use rustc_middle::ty::{ self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, }; @@ -430,8 +430,17 @@ pub(crate) fn check_generic_arg_count( prohibit_assoc_item_constraint(cx, c, None); } - let explicit_late_bound = - prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos); + let tcx = cx.tcx(); + let parent_def = tcx.hir_get_parent_item(seg.hir_id).def_id; + + // Suppress this warning for delegations as it is compiler generated and lifetimes are + // propagated while late-bound lifetimes may be present. + let explicit_late_bound = match tcx.hir_opt_delegation_info(parent_def) { + Some(DelegationInfo { child_seg_id, .. }) if seg.hir_id == *child_seg_id => { + ExplicitLateBound::No + } + _ => prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos), + }; let mut invalid_args = vec![]; @@ -458,7 +467,7 @@ pub(crate) fn check_generic_arg_count( }; let reported = cx.dcx().emit_err(WrongNumberOfGenericArgs::new( - cx.tcx(), + tcx, gen_args_info, seg, gen_params, @@ -536,20 +545,19 @@ pub(crate) fn check_generic_arg_count( .map(|param| param.name) .collect(); if constraint_names == param_names { - let has_assoc_ty_with_same_name = - if let DefKind::Trait = cx.tcx().def_kind(def_id) { - gen_args.constraints.iter().any(|constraint| { - traits::supertrait_def_ids(cx.tcx(), def_id).any(|trait_did| { - cx.probe_trait_that_defines_assoc_item( - trait_did, - ty::AssocTag::Type, - constraint.ident, - ) - }) + let has_assoc_ty_with_same_name = if let DefKind::Trait = tcx.def_kind(def_id) { + gen_args.constraints.iter().any(|constraint| { + traits::supertrait_def_ids(tcx, def_id).any(|trait_did| { + cx.probe_trait_that_defines_assoc_item( + trait_did, + ty::AssocTag::Type, + constraint.ident, + ) }) - } else { - false - }; + }) + } else { + false + }; // We set this to true and delay emitting `WrongNumberOfGenericArgs` // to provide a succinct error for cases like issue #113073, // but only if when we don't have any assoc type with the same name with a @@ -573,7 +581,7 @@ pub(crate) fn check_generic_arg_count( let reported = gen_args.has_err().unwrap_or_else(|| { cx.dcx() .create_err(WrongNumberOfGenericArgs::new( - cx.tcx(), + tcx, gen_args_info, seg, gen_params, diff --git a/tests/pretty/delegation-self-rename.pp b/tests/pretty/delegation-self-rename.pp index 7f7afc403607b..526021c061178 100644 --- a/tests/pretty/delegation-self-rename.pp +++ b/tests/pretty/delegation-self-rename.pp @@ -19,15 +19,18 @@ #[attr = Inline(Hint)] fn foo<'a, Self, A, const B: _, const B2: _, T, U, impl FnOnce() -> usize>(self: _, arg1: _) -> _ where - 'a:'a { Trait::<'a, A, B>::foo::(self, arg1) } + 'a:'a { >::foo::(self, arg1) } #[attr = Inline(Hint)] fn bar usize>(self: _, arg1: _) - -> _ { Trait::<'static, (), true>::foo::(self, arg1) } + -> + _ { + >::foo::(self, arg1) +} #[attr = Inline(Hint)] fn foo2<'a, This, A, const B: _, const B2: _, T, U, impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where - 'a:'a { foo::(arg0, arg1) } + 'a:'a { foo::<'a, This, A, B, B2, T, U>(arg0, arg1) } #[attr = Inline(Hint)] fn bar2 usize>(arg0: _, arg1: _) -> _ { bar::(arg0, arg1) } @@ -36,7 +39,7 @@ #[attr = Inline(Hint)] fn foo3<'a, This, A, const B: _, const B2: _, T, U, impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where - 'a:'a { foo2::(arg0, arg1) } + 'a:'a { foo2::<'a, This, A, B, B2, T, U>(arg0, arg1) } #[attr = Inline(Hint)] fn bar3 usize>(arg0: _, arg1: _) -> _ { bar2::(arg0, arg1) } @@ -47,7 +50,7 @@ #[attr = Inline(Hint)] fn foo4<'a, This, A, const B: _, const B2: _, T, U, impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where - 'a:'a { <() as Trait2>::foo3::(arg0, arg1) } + 'a:'a { <() as Trait2>::foo3::<'a, This, A, B, B2, T, U>(arg0, arg1) } #[attr = Inline(Hint)] fn bar4 usize>(arg0: _, arg1: _) -> _ { <() as Trait2>::bar3::(arg0, arg1) } diff --git a/tests/ui/delegation/generics/free-fn-to-trait-infer.rs b/tests/ui/delegation/generics/free-fn-to-trait-infer.rs deleted file mode 100644 index 0a0665b752681..0000000000000 --- a/tests/ui/delegation/generics/free-fn-to-trait-infer.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -Z deduplicate-diagnostics=yes - -#![feature(fn_delegation)] - -trait Trait { - fn foo(&self, _: U, _: T) {} -} - -impl Trait for u8 {} - -reuse Trait::<_>::foo:: as generic_arguments1; -//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions -reuse >::foo as generic_arguments2; -//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions -reuse <_ as Trait<_>>::foo as generic_arguments3; -//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions -//~| ERROR the placeholder `_` is not allowed within types on item signatures for functions - -fn main() {} diff --git a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr b/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr deleted file mode 100644 index f1e9231cc4050..0000000000000 --- a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/free-fn-to-trait-infer.rs:11:15 - | -LL | reuse Trait::<_>::foo:: as generic_arguments1; - | ^ not allowed in type signatures - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/free-fn-to-trait-infer.rs:13:20 - | -LL | reuse >::foo as generic_arguments2; - | ^ not allowed in type signatures - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/free-fn-to-trait-infer.rs:15:8 - | -LL | reuse <_ as Trait<_>>::foo as generic_arguments3; - | ^ not allowed in type signatures - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/free-fn-to-trait-infer.rs:15:19 - | -LL | reuse <_ as Trait<_>>::foo as generic_arguments3; - | ^ not allowed in type signatures - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/delegation/generics/free-to-trait-static-reuse.rs b/tests/ui/delegation/generics/free-to-trait-static-reuse.rs index e3d0bdbc7e9b0..3f52209ded317 100644 --- a/tests/ui/delegation/generics/free-to-trait-static-reuse.rs +++ b/tests/ui/delegation/generics/free-to-trait-static-reuse.rs @@ -20,17 +20,9 @@ reuse ::static_method as bar { self + 1 } reuse ::static_method::<'static, Vec, false> as bar2; reuse Trait::static_method as error { self - 123 } -//~^ ERROR: type annotations needed -//~| ERROR: delegation self type is not specified reuse Trait::<'static, i32, 123>::static_method as error2; -//~^ ERROR: type annotations needed -//~| ERROR: delegation self type is not specified reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; -//~^ ERROR: type annotations needed -//~| ERROR: delegation self type is not specified reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } -//~^ ERROR: type annotations needed -//~| ERROR: delegation self type is not specified reuse ::static_method as error5; //~^ ERROR: the trait bound `String: Trait<'a, T, X>` is not satisfied diff --git a/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr b/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr index 8d87b9376acd4..04f5e60044cdc 100644 --- a/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr +++ b/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr @@ -1,43 +1,11 @@ -error: delegation self type is not specified - --> $DIR/free-to-trait-static-reuse.rs:22:14 - | -LL | reuse Trait::static_method as error { self - 123 } - | ^^^^^^^^^^^^^ - | - = help: consider explicitly specifying self type: `reuse ::function` - -error: delegation self type is not specified - --> $DIR/free-to-trait-static-reuse.rs:25:35 - | -LL | reuse Trait::<'static, i32, 123>::static_method as error2; - | ^^^^^^^^^^^^^ - | - = help: consider explicitly specifying self type: `reuse ::function` - -error: delegation self type is not specified - --> $DIR/free-to-trait-static-reuse.rs:28:35 - | -LL | reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; - | ^^^^^^^^^^^^^ - | - = help: consider explicitly specifying self type: `reuse ::function` - -error: delegation self type is not specified - --> $DIR/free-to-trait-static-reuse.rs:31:14 - | -LL | reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } - | ^^^^^^^^^^^^^ - | - = help: consider explicitly specifying self type: `reuse ::function` - error[E0277]: the trait bound `Struct: Bound` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:39:49 + --> $DIR/free-to-trait-static-reuse.rs:31:49 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^ unsatisfied trait bound | help: the trait `Bound` is not implemented for `Struct` - --> $DIR/free-to-trait-static-reuse.rs:38:1 + --> $DIR/free-to-trait-static-reuse.rs:30:1 | LL | struct Struct; | ^^^^^^^^^^^^^ @@ -55,68 +23,8 @@ LL | where LL | Self: Bound, | ^^^^^^^^ required by this bound in `Trait` -error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:22:14 - | -LL | reuse Trait::static_method as error { self - 123 } - | ^^^^^^^^^^^^^ cannot infer type - | -note: multiple `impl`s satisfying `_: Trait<'a, T, X>` found - --> $DIR/free-to-trait-static-reuse.rs:14:1 - | -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:25:35 - | -LL | reuse Trait::<'static, i32, 123>::static_method as error2; - | ^^^^^^^^^^^^^ cannot infer type - | -note: multiple `impl`s satisfying `_: Trait<'static, i32, 123>` found - --> $DIR/free-to-trait-static-reuse.rs:14:1 - | -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:28:35 - | -LL | reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; - | ^^^^^^^^^^^^^ cannot infer type - | -note: multiple `impl`s satisfying `_: Trait<'static, i32, 123>` found - --> $DIR/free-to-trait-static-reuse.rs:14:1 - | -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:31:14 - | -LL | reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } - | ^^^^^^^^^^^^^ cannot infer type - | -note: multiple `impl`s satisfying `_: Trait<'a, T, X>` found - --> $DIR/free-to-trait-static-reuse.rs:14:1 - | -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0277]: the trait bound `String: Trait<'a, T, X>` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:35:8 + --> $DIR/free-to-trait-static-reuse.rs:27:8 | LL | reuse ::static_method as error5; | ^^^^^^ the trait `Trait<'a, T, X>` is not implemented for `String` @@ -131,13 +39,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Struct` error[E0277]: the trait bound `Struct: Bound` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:42:8 + --> $DIR/free-to-trait-static-reuse.rs:34:8 | LL | reuse ::static_method as error6; | ^^^^^^ unsatisfied trait bound | help: the trait `Bound` is not implemented for `Struct` - --> $DIR/free-to-trait-static-reuse.rs:38:1 + --> $DIR/free-to-trait-static-reuse.rs:30:1 | LL | struct Struct; | ^^^^^^^^^^^^^ @@ -155,7 +63,6 @@ LL | { LL | fn static_method<'c: 'c, U, const B: bool>(x: usize) {} | ------------- required by a bound in this associated function -error: aborting due to 11 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0283. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.rs b/tests/ui/delegation/generics/generics-gen-args-errors.rs index 4e1ac0a5e4176..6a8d1674fe184 100644 --- a/tests/ui/delegation/generics/generics-gen-args-errors.rs +++ b/tests/ui/delegation/generics/generics-gen-args-errors.rs @@ -44,8 +44,6 @@ mod test_2 { fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} reuse foo::<> as bar1; - //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions - //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature reuse foo:: as bar2; //~^ ERROR: function takes 3 generic arguments but 2 generic arguments were supplied @@ -54,9 +52,9 @@ mod test_2 { reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3; //~^ ERROR: use of undeclared lifetime name `'asdasd` - //~| ERROR: function takes 2 lifetime arguments but 5 lifetime arguments were supplied - //~| ERROR: function takes 3 generic arguments but 2 generic arguments were supplied - //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: function takes 2 lifetime arguments but 6 lifetime arguments were supplied + //~| ERROR: function takes 3 generic arguments but 1 generic argument was supplied + //~| ERROR: wrong infer used: expected '_, found: _ reuse foo:: as bar4; //~^ ERROR: cannot find type `asdasd` in this scope @@ -131,12 +129,13 @@ mod test_3 { //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; - //~^ ERROR: trait takes 3 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR: trait takes 2 generic arguments but 5 generic arguments were supplied + //~^ ERROR: trait takes 3 lifetime arguments but 2 lifetime arguments were supplied + //~| ERROR: trait takes 2 generic arguments but 4 generic arguments were supplied //~| ERROR: method takes 2 generic arguments but 5 generic arguments were supplied //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: wrong infer used: expected '_, found: _ } fn main() {} diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.stderr b/tests/ui/delegation/generics/generics-gen-args-errors.stderr index 7aa1766dfef89..c08e23e6c016a 100644 --- a/tests/ui/delegation/generics/generics-gen-args-errors.stderr +++ b/tests/ui/delegation/generics/generics-gen-args-errors.stderr @@ -38,7 +38,7 @@ LL | reuse foo:: as xd; = note: nested items are independent from their parent item for everything except for privacy and name resolution error[E0261]: use of undeclared lifetime name `'asdasd` - --> $DIR/generics-gen-args-errors.rs:55:29 + --> $DIR/generics-gen-args-errors.rs:53:29 | LL | reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3; | ^^^^^^^ undeclared lifetime @@ -49,7 +49,7 @@ LL | reuse foo'asdasd, ::<'static, _, 'asdasd, 'static, 'static, 'static, _> | ++++++++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/generics-gen-args-errors.rs:77:50 + --> $DIR/generics-gen-args-errors.rs:75:50 | LL | reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7; | ^^ undeclared lifetime @@ -103,65 +103,77 @@ LL | fn check() { | +++++ error[E0425]: cannot find type `asdasd` in this scope - --> $DIR/generics-gen-args-errors.rs:61:39 + --> $DIR/generics-gen-args-errors.rs:59:39 | LL | reuse foo:: as bar4; | ^^^^^^ not found in this scope error[E0425]: cannot find type `asd` in this scope - --> $DIR/generics-gen-args-errors.rs:71:22 + --> $DIR/generics-gen-args-errors.rs:69:22 | LL | reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6; | ^^^ not found in this scope error[E0425]: cannot find type `asd` in this scope - --> $DIR/generics-gen-args-errors.rs:77:27 + --> $DIR/generics-gen-args-errors.rs:75:27 | LL | reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7; | ^^^ not found in this scope error[E0425]: cannot find type `asd` in this scope - --> $DIR/generics-gen-args-errors.rs:94:19 + --> $DIR/generics-gen-args-errors.rs:92:19 | LL | reuse Trait::::foo as bar1; | ^^^ not found in this scope error[E0425]: cannot find type `asd` in this scope - --> $DIR/generics-gen-args-errors.rs:94:24 + --> $DIR/generics-gen-args-errors.rs:92:24 | LL | reuse Trait::::foo as bar1; | ^^^ not found in this scope error[E0425]: cannot find type `asd` in this scope - --> $DIR/generics-gen-args-errors.rs:94:29 + --> $DIR/generics-gen-args-errors.rs:92:29 | LL | reuse Trait::::foo as bar1; | ^^^ not found in this scope error[E0425]: cannot find type `asd` in this scope - --> $DIR/generics-gen-args-errors.rs:94:34 + --> $DIR/generics-gen-args-errors.rs:92:34 | LL | reuse Trait::::foo as bar1; | ^^^ not found in this scope error[E0425]: cannot find type `asd` in this scope - --> $DIR/generics-gen-args-errors.rs:94:39 + --> $DIR/generics-gen-args-errors.rs:92:39 | LL | reuse Trait::::foo as bar1; | ^^^ not found in this scope error[E0425]: cannot find type `asdasa` in this scope - --> $DIR/generics-gen-args-errors.rs:94:44 + --> $DIR/generics-gen-args-errors.rs:92:44 | LL | reuse Trait::::foo as bar1; | ^^^^^^ not found in this scope error[E0425]: cannot find type `DDDD` in this scope - --> $DIR/generics-gen-args-errors.rs:124:34 + --> $DIR/generics-gen-args-errors.rs:122:34 | LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | ^^^^ not found in this scope +error: wrong infer used: expected '_, found: _ + --> $DIR/generics-gen-args-errors.rs:53:26 + | +LL | reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3; + | ^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/generics-gen-args-errors.rs:131:33 + | +LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; + | ^ + error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied --> $DIR/generics-gen-args-errors.rs:33:15 | @@ -184,20 +196,8 @@ error: inferred lifetimes are not allowed in delegations as we need to inherit s LL | reuse foo:: as xd; | ^^^ -error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:46:11 - | -LL | reuse foo::<> as bar1; - | ^^^ - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/generics-gen-args-errors.rs:46:11 - | -LL | reuse foo::<> as bar1; - | ^^^ not allowed in type signatures - error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:50:11 + --> $DIR/generics-gen-args-errors.rs:48:11 | LL | reuse foo:: as bar2; | ^^^ expected 2 lifetime arguments @@ -213,7 +213,7 @@ LL | reuse foo::<'a, 'b, String, String> as bar2; | +++++++ error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:50:11 + --> $DIR/generics-gen-args-errors.rs:48:11 | LL | reuse foo:: as bar2; | ^^^ ------ ------ supplied 2 generic arguments @@ -231,16 +231,16 @@ LL | reuse foo:: as bar2; | +++ error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:50:11 + --> $DIR/generics-gen-args-errors.rs:48:11 | LL | reuse foo:: as bar2; | ^^^ -error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:55:11 +error[E0107]: function takes 2 lifetime arguments but 6 lifetime arguments were supplied + --> $DIR/generics-gen-args-errors.rs:53:11 | LL | reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3; - | ^^^ --------------------------- help: remove the lifetime arguments + | ^^^------------------------------------------------- help: remove the lifetime arguments | | | expected 2 lifetime arguments | @@ -250,30 +250,24 @@ note: function defined here, with 2 lifetime parameters: `'a`, `'b` LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} | ^^^ -- -- -error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:55:11 +error[E0107]: function takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/generics-gen-args-errors.rs:53:11 | LL | reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3; - | ^^^ expected 3 generic arguments ------- - supplied 2 generic arguments + | ^^^ expected 3 generic arguments - supplied 1 generic argument | note: function defined here, with 3 generic parameters: `T`, `U`, `N` --> $DIR/generics-gen-args-errors.rs:44:8 | LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} | ^^^ - - -------------- -help: add missing generic argument +help: add missing generic arguments | -LL | reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _, N> as bar3; - | +++ - -error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:55:11 - | -LL | reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _> as bar3; - | ^^^ +LL | reuse foo::<'static, _, 'asdasd, 'static, 'static, 'static, _, U, N> as bar3; + | ++++++ error[E0107]: function takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/generics-gen-args-errors.rs:61:11 + --> $DIR/generics-gen-args-errors.rs:59:11 | LL | reuse foo:: as bar4; | ^^^ ------ supplied 1 lifetime argument @@ -291,13 +285,13 @@ LL | reuse foo:: as bar4; | +++++++++ error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:61:11 + --> $DIR/generics-gen-args-errors.rs:59:11 | LL | reuse foo:: as bar4; | ^^^ error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:66:11 + --> $DIR/generics-gen-args-errors.rs:64:11 | LL | reuse foo::<1, 2, _, 4, 5, _> as bar5; | ^^^ expected 2 lifetime arguments @@ -313,10 +307,10 @@ LL | reuse foo::<'a, 'b, 1, 2, _, 4, 5, _> as bar5; | +++++++ error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:66:11 + --> $DIR/generics-gen-args-errors.rs:64:11 | LL | reuse foo::<1, 2, _, 4, 5, _> as bar5; - | ^^^ --------- help: remove the unnecessary generic arguments + | ^^^------------------- help: remove the unnecessary generic arguments | | | expected 3 generic arguments | @@ -327,13 +321,13 @@ LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} | ^^^ - - -------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:66:11 + --> $DIR/generics-gen-args-errors.rs:64:11 | LL | reuse foo::<1, 2, _, 4, 5, _> as bar5; | ^^^ error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:71:11 + --> $DIR/generics-gen-args-errors.rs:69:11 | LL | reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6; | ^^^ expected 2 lifetime arguments @@ -349,7 +343,7 @@ LL | reuse foo::<'a, 'b, 1, 2,asd,String, { let x = 0; }> as bar6; | +++++++ error[E0107]: function takes 3 generic arguments but 5 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:71:11 + --> $DIR/generics-gen-args-errors.rs:69:11 | LL | reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6; | ^^^ ----------------------- help: remove the unnecessary generic arguments @@ -363,25 +357,25 @@ LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} | ^^^ - - -------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:71:11 + --> $DIR/generics-gen-args-errors.rs:69:11 | LL | reuse foo::<1, 2,asd,String, { let x = 0; }> as bar6; | ^^^ error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:77:11 + --> $DIR/generics-gen-args-errors.rs:75:11 | LL | reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7; | ^^^ error[E0747]: constant provided when a type was expected - --> $DIR/generics-gen-args-errors.rs:77:17 + --> $DIR/generics-gen-args-errors.rs:75:17 | LL | reuse foo::<"asdasd", asd, "askdn", 'static, 'a> as bar7; | ^^^^^^^^ error[E0107]: function takes 2 lifetime arguments but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:83:11 + --> $DIR/generics-gen-args-errors.rs:81:11 | LL | reuse foo::<{}, {}, {}> as bar8; | ^^^ expected 2 lifetime arguments @@ -397,19 +391,19 @@ LL | reuse foo::<'a, 'b, {}, {}, {}> as bar8; | +++++++ error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:83:11 + --> $DIR/generics-gen-args-errors.rs:81:11 | LL | reuse foo::<{}, {}, {}> as bar8; | ^^^ error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:94:11 + --> $DIR/generics-gen-args-errors.rs:92:11 | LL | reuse Trait::::foo as bar1; | ^^^^^ expected 3 lifetime arguments | note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ -- -- -- @@ -419,7 +413,7 @@ LL | reuse Trait::<'b, 'c, 'a, asd, asd, asd, asd, asd, asdasa>::foo as bar1 | +++++++++++ error[E0107]: trait takes 2 generic arguments but 6 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:94:11 + --> $DIR/generics-gen-args-errors.rs:92:11 | LL | reuse Trait::::foo as bar1; | ^^^^^ ----------------------- help: remove the unnecessary generic arguments @@ -427,19 +421,19 @@ LL | reuse Trait::::foo as bar1; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `T`, `N` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ - -------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:94:11 + --> $DIR/generics-gen-args-errors.rs:92:11 | LL | reuse Trait::::foo as bar1; | ^^^^^ error[E0107]: trait takes 3 lifetime arguments but 2 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:105:11 + --> $DIR/generics-gen-args-errors.rs:103:11 | LL | reuse Trait::<'static, 'static>::foo as bar2; | ^^^^^ ------- ------- supplied 2 lifetime arguments @@ -447,7 +441,7 @@ LL | reuse Trait::<'static, 'static>::foo as bar2; | expected 3 lifetime arguments | note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ -- -- -- @@ -457,25 +451,25 @@ LL | reuse Trait::<'static, 'static, 'static>::foo as bar2; | +++++++++ error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:105:11 + --> $DIR/generics-gen-args-errors.rs:103:11 | LL | reuse Trait::<'static, 'static>::foo as bar2; | ^^^^^ error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/generics-gen-args-errors.rs:105:11 + --> $DIR/generics-gen-args-errors.rs:103:11 | LL | reuse Trait::<'static, 'static>::foo as bar2; | ^^^^^ not allowed in type signatures error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:109:11 + --> $DIR/generics-gen-args-errors.rs:107:11 | LL | reuse Trait::<1, 2, 3, 4, 5>::foo as bar3; | ^^^^^ expected 3 lifetime arguments | note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ -- -- -- @@ -485,7 +479,7 @@ LL | reuse Trait::<'b, 'c, 'a, 1, 2, 3, 4, 5>::foo as bar3; | +++++++++++ error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:109:11 + --> $DIR/generics-gen-args-errors.rs:107:11 | LL | reuse Trait::<1, 2, 3, 4, 5>::foo as bar3; | ^^^^^ --------- help: remove the unnecessary generic arguments @@ -493,25 +487,25 @@ LL | reuse Trait::<1, 2, 3, 4, 5>::foo as bar3; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `T`, `N` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ - -------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:109:11 + --> $DIR/generics-gen-args-errors.rs:107:11 | LL | reuse Trait::<1, 2, 3, 4, 5>::foo as bar3; | ^^^^^ error[E0107]: trait takes 3 lifetime arguments but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:114:11 + --> $DIR/generics-gen-args-errors.rs:112:11 | LL | reuse Trait::<1, 2, true>::foo as bar4; | ^^^^^ expected 3 lifetime arguments | note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ -- -- -- @@ -521,7 +515,7 @@ LL | reuse Trait::<'b, 'c, 'a, 1, 2, true>::foo as bar4; | +++++++++++ error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:114:11 + --> $DIR/generics-gen-args-errors.rs:112:11 | LL | reuse Trait::<1, 2, true>::foo as bar4; | ^^^^^ ------ help: remove the unnecessary generic argument @@ -529,19 +523,19 @@ LL | reuse Trait::<1, 2, true>::foo as bar4; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `T`, `N` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ - -------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:114:11 + --> $DIR/generics-gen-args-errors.rs:112:11 | LL | reuse Trait::<1, 2, true>::foo as bar4; | ^^^^^ error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/generics-gen-args-errors.rs:119:11 + --> $DIR/generics-gen-args-errors.rs:117:11 | LL | reuse Trait::<'static>::foo as bar5; | ^^^^^ ------- supplied 1 lifetime argument @@ -549,7 +543,7 @@ LL | reuse Trait::<'static>::foo as bar5; | expected 3 lifetime arguments | note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ -- -- -- @@ -559,19 +553,19 @@ LL | reuse Trait::<'static, 'static, 'static>::foo as bar5; | ++++++++++++++++++ error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:119:11 + --> $DIR/generics-gen-args-errors.rs:117:11 | LL | reuse Trait::<'static>::foo as bar5; | ^^^^^ error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/generics-gen-args-errors.rs:119:11 + --> $DIR/generics-gen-args-errors.rs:117:11 | LL | reuse Trait::<'static>::foo as bar5; | ^^^^^ not allowed in type signatures error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/generics-gen-args-errors.rs:124:11 + --> $DIR/generics-gen-args-errors.rs:122:11 | LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | ^^^^^ - supplied 1 lifetime argument @@ -579,7 +573,7 @@ LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | expected 3 lifetime arguments | note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ -- -- -- @@ -589,7 +583,7 @@ LL | reuse Trait::<1, 'static, 'static, 2, 'static, DDDD>::foo::<1, 2, 3, 4, | ++++++++++++++++++ error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:124:11 + --> $DIR/generics-gen-args-errors.rs:122:11 | LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | ^^^^^ --------------- help: remove the unnecessary generic argument @@ -597,25 +591,25 @@ LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `T`, `N` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ - -------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:124:11 + --> $DIR/generics-gen-args-errors.rs:122:11 | LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | ^^^^^ error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:124:41 + --> $DIR/generics-gen-args-errors.rs:122:41 | LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | ^^^ expected 1 lifetime argument | note: method defined here, with 1 lifetime parameter: `'d` - --> $DIR/generics-gen-args-errors.rs:91:12 + --> $DIR/generics-gen-args-errors.rs:89:12 | LL | fn foo<'d: 'd, U, const M: bool>(self) {} | ^^^ -- @@ -625,7 +619,7 @@ LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<'d, 1, 2, 3, 4, 5, 6> as bar6 | +++ error[E0107]: method takes 2 generic arguments but 6 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:124:41 + --> $DIR/generics-gen-args-errors.rs:122:41 | LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | ^^^ ------------ help: remove the unnecessary generic arguments @@ -633,73 +627,73 @@ LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | expected 2 generic arguments | note: method defined here, with 2 generic parameters: `U`, `M` - --> $DIR/generics-gen-args-errors.rs:91:12 + --> $DIR/generics-gen-args-errors.rs:89:12 | LL | fn foo<'d: 'd, U, const M: bool>(self) {} | ^^^ - ------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:124:41 + --> $DIR/generics-gen-args-errors.rs:122:41 | LL | reuse Trait::<1, 2, 'static, DDDD>::foo::<1, 2, 3, 4, 5, 6> as bar6; | ^^^ -error[E0107]: trait takes 3 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/generics-gen-args-errors.rs:133:11 +error[E0107]: trait takes 3 lifetime arguments but 2 lifetime arguments were supplied + --> $DIR/generics-gen-args-errors.rs:131:11 | LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; - | ^^^^^ ----- supplied 1 lifetime argument + | ^^^^^ ----- ----- supplied 2 lifetime arguments | | | expected 3 lifetime arguments | note: trait defined here, with 3 lifetime parameters: `'b`, `'c`, `'a` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ -- -- -- -help: add missing lifetime arguments +help: add missing lifetime argument | -LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; - | ++++++++++++++++++ +LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; + | ++++ -error[E0107]: trait takes 2 generic arguments but 5 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:133:11 +error[E0107]: trait takes 2 generic arguments but 4 generic arguments were supplied + --> $DIR/generics-gen-args-errors.rs:131:11 | LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; - | ^^^^^ --- help: remove the unnecessary generic argument + | ^^^^^ ------------------------- help: remove the unnecessary generic arguments | | | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `T`, `N` - --> $DIR/generics-gen-args-errors.rs:90:11 + --> $DIR/generics-gen-args-errors.rs:88:11 | LL | trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { | ^^^^^ - -------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:133:11 + --> $DIR/generics-gen-args-errors.rs:131:11 | LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; | ^^^^^ error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/generics-gen-args-errors.rs:133:59 + --> $DIR/generics-gen-args-errors.rs:131:59 | LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; | ^^^ expected 1 lifetime argument | note: method defined here, with 1 lifetime parameter: `'d` - --> $DIR/generics-gen-args-errors.rs:91:12 + --> $DIR/generics-gen-args-errors.rs:89:12 | LL | fn foo<'d: 'd, U, const M: bool>(self) {} | ^^^ -- help: add missing lifetime argument | -LL | reuse Trait::::foo::<'d, 1, 2, 3, _, 6> as bar7; +LL | reuse Trait::::foo::<'a, 1, 2, 3, _, 6> as bar7; | +++ error[E0107]: method takes 2 generic arguments but 5 generic arguments were supplied - --> $DIR/generics-gen-args-errors.rs:133:59 + --> $DIR/generics-gen-args-errors.rs:131:59 | LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; | ^^^ --------- help: remove the unnecessary generic arguments @@ -707,13 +701,13 @@ LL | reuse Trait::::foo::<1, 2, 3, _, | expected 2 generic arguments | note: method defined here, with 2 generic parameters: `U`, `M` - --> $DIR/generics-gen-args-errors.rs:91:12 + --> $DIR/generics-gen-args-errors.rs:89:12 | LL | fn foo<'d: 'd, U, const M: bool>(self) {} | ^^^ - ------------- error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/generics-gen-args-errors.rs:133:59 + --> $DIR/generics-gen-args-errors.rs:131:59 | LL | reuse Trait::::foo::<1, 2, 3, _, 6> as bar7; | ^^^ @@ -789,12 +783,12 @@ LL | reuse foo:: as xd; | + + error[E0747]: constant provided when a type was expected - --> $DIR/generics-gen-args-errors.rs:83:17 + --> $DIR/generics-gen-args-errors.rs:81:17 | LL | reuse foo::<{}, {}, {}> as bar8; | ^^ -error: aborting due to 75 previous errors +error: aborting due to 74 previous errors Some errors have detailed explanations: E0107, E0121, E0261, E0401, E0423, E0425, E0747. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/generics/infers.rs b/tests/ui/delegation/generics/infers.rs new file mode 100644 index 0000000000000..d9205f510a7b4 --- /dev/null +++ b/tests/ui/delegation/generics/infers.rs @@ -0,0 +1,356 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + +#![feature(fn_delegation)] + +// Some interesting cases: +mod selected_tests { + mod different_infers { + fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + + // Should differentiate between lifetime and types/consts infers. + reuse foo::<_, '_, '_, '_> as bar; + //~^ ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + } + + mod self_type { + trait Trait<'a, X> { + fn method<'b: 'b, const M: usize>(&self) {} + fn r#static<'b, Y, const B: bool>() {} + } + + impl<'a, X> Trait<'a, X> for () {} + + reuse Trait::<'_, _>::method::<'_, _> as foo; + + reuse <_ as Trait<'_, _>>::method::<'_, _> as foo1; + reuse <() as Trait<'_, _>>::method::<'_, _> as foo2; + + reuse <_ as Trait<'_, _>>::r#static::<_, _> as foo3; + reuse <() as Trait<'_, _>>::r#static::<_, _> as foo4; + + reuse Trait::<'_, _>::r#static::<_, _> as foo5; + } + + mod late_bound_lifetimes { + fn foo<'a, 'b, 'c: 'c, 'd>(_: &'a &'b &'c &'d ()) {} + + // 'c corresponds to infer. + reuse foo::<'_> as foo1; + + // Only 'c is generated in desugaring, second infer remains just infer in call path. + reuse foo::<'_, '_> as foo2; + //~^ ERROR: function takes 1 lifetime argument but 2 lifetime arguments were supplied + + reuse foo as foo3; + reuse foo::<'static> as foo4; + } + + mod non_angle_bracketed_args { + fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + + reuse foo::('_, _, _, _) as bar; + //~^ ERROR: lifetimes must be followed by `+` to form a trait object type + //~| ERROR: at least one trait is required for an object type + //~| ERROR: parenthesized type parameters may only be used with a `Fn` trait [E0214] + //~| ERROR: function takes 1 lifetime argument but 0 lifetime arguments were supplied [E0107] + //~| ERROR: function takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + } +} + +// All other stuff: +mod legacy_tests { + trait Trait { + fn foo(&self, _: U, _: T) {} + } + + impl Trait for u8 {} + + reuse Trait::<_>::foo:: as generic_arguments1; + reuse >::foo as generic_arguments2; + reuse <_ as Trait<_>>::foo as generic_arguments3; +} + +mod free_to_free { + fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + + reuse foo::<> as foo1; + reuse foo::<'_, _, _, _> as foo2; + reuse foo::<'static, String, _, _> as foo3; + reuse foo::<'_, _, 123, _> as foo4; + + reuse foo::<'_, '_, '_, _, _, _,> as foo5; + //~^ ERROR: function takes 3 generic arguments but 5 generic arguments were supplied + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + //~^ ERROR: function takes 3 generic arguments but 6 generic arguments were supplied [E0107] + //~| ERROR: function takes 1 lifetime argument but 3 lifetime arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse foo::<_, '_, _, _> as foo7; + //~^ ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse foo::<'_, '_, '_, '_> as foo8; + //~^ ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse foo::<_> as foo9; + //~^ ERROR: function takes 3 generic arguments but 0 generic arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + + reuse foo::, _, _, ()> as foo10; + //~^ ERROR: function takes 1 lifetime argument but 0 lifetime arguments were supplied [E0107] + //~| ERROR: function takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: struct takes 0 lifetime arguments but 1 lifetime argument was supplied [E0107] + //~| ERROR: struct takes at least 1 generic argument but 0 generic arguments were supplied [E0107] + + reuse foo::, _, _, ()> as foo11; + //~^ ERROR: function takes 1 lifetime argument but 0 lifetime arguments were supplied [E0107] + //~| ERROR: function takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + + reuse foo::<'____, ___, _, ___> as foo12; + //~^ ERROR: use of undeclared lifetime name `'____` [E0261] + //~| ERROR: cannot find type `___` in this scope [E0425] + //~| ERROR: cannot find type `___` in this scope [E0425] + + reuse foo::<'_, Vec<_>, Vec>, _> as foo13; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: type provided when a constant was expected [E0747] + + reuse foo::<'_, unresolved_, _, _> as foo14; + //~^ ERROR: cannot find type `unresolved_` in this scope + + reuse foo::<_, _, _> as foo15; + //~^ ERROR: function takes 3 generic arguments but 2 generic arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ +} + +mod free_to_trait { + pub trait Trait<'a, 'b, X, const C: usize, Y> { + fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + } + + struct X; + impl<'a, 'b, Some, Params, X, const C: usize, Y> Trait<'a, 'b, X, C, Y> for X {} + //~^ ERROR: the type parameter `Some` is not constrained by the impl trait, self type, or predicates [E0207] + //~| ERROR: the type parameter `Params` is not constrained by the impl trait, self type, or predicates [E0207] + + mod child_only { + use super::*; + + reuse Trait::foo::<> as foo1; + reuse Trait::foo::<'_, _, _, _> as foo2; + reuse Trait::foo::<'static, String, _, _> as foo3; + reuse Trait::foo::<'_, _, 123, _> as foo4; + + reuse Trait::foo::<'_, '_, '_, _, _, _,> as foo5; + //~^ ERROR: method takes 3 generic arguments but 5 generic arguments were supplied + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + //~^ ERROR: method takes 3 generic arguments but 6 generic arguments were supplied [E0107] + //~| ERROR: method takes 1 lifetime argument but 3 lifetime arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::foo::<_, '_, _, _> as foo7; + //~^ ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::foo::<'_, '_, '_, '_> as foo8; + //~^ ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::foo::<_> as foo9; + //~^ ERROR: method takes 3 generic arguments but 0 generic arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + + reuse Trait::foo::, _, _, ()> as foo10; + //~^ ERROR: method takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: struct takes 0 lifetime arguments but 1 lifetime argument was supplied [E0107] + //~| ERROR: struct takes at least 1 generic argument but 0 generic arguments were supplied [E0107] + //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied + + reuse Trait::foo::, _, _, ()> as foo11; + //~^ ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied [E0107] + //~| ERROR: method takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + + reuse Trait::foo::<'____, ___, _, ___> as foo12; + //~^ ERROR: use of undeclared lifetime name `'____` [E0261] + //~| ERROR: cannot find type `___` in this scope [E0425] + //~| ERROR: cannot find type `___` in this scope [E0425] + + reuse Trait::foo::<'_, Vec<_>, Vec>, _> as foo13; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: type provided when a constant was expected [E0747] + + reuse Trait::foo::<'_, unresolved_, _, _> as foo14; + //~^ ERROR: cannot find type `unresolved_` in this scope + + reuse Trait::foo::<_, _, _> as foo15; + //~^ ERROR: method takes 3 generic arguments but 2 generic arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + } + + mod parent_only { + use super::*; + + reuse Trait::<'_, 'static, _, _, _>::foo as foo1; + reuse Trait::<'_, '_, _, _, _>::foo as foo2; + + reuse Trait::<'_, (), _, '_, _>::foo as foo3; + //~^ ERROR: trait takes 2 lifetime arguments but 1 lifetime argument was supplied [E0107] + //~| ERROR: trait takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<>::foo as foo4; + + reuse Trait::<_, _>::foo as foo5; + //~^ ERROR: trait takes 3 generic arguments but 0 generic arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected '_, found: _ + + reuse Trait::<'_, '_>::foo as foo6; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions + + reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo as foo7; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + + reuse Trait::<'static, 'static, (), 123, ()>::foo as foo8; + reuse Trait::<'static, 'static, _, _, _>::foo as foo9; + + reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo as foo10; + //~^ ERROR: trait takes 3 generic arguments but 7 generic arguments were supplied + + reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_, '_>::foo as foo11; + //~^ ERROR: trait takes 2 lifetime arguments but 6 lifetime arguments were supplied + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<'static, 'static, _>::foo as foo12; + //~^ ERROR: trait takes 3 generic arguments but 1 generic argument was supplied + } + + mod parent_and_child_random { + use super::*; + + reuse Trait::<'_, 'static, _, _, _>::foo::<> as foo1; + reuse Trait::<'_, '_, _, _, _>::foo::<'_, _, _, _> as foo2; + + reuse Trait::<'_, (), _, '_, _>::foo::<'static, String, _, _> as foo3; + //~^ ERROR: trait takes 2 lifetime arguments but 1 lifetime argument was supplied [E0107] + //~| ERROR: trait takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<>::foo::<'_, _, 123, _> as foo4; + + reuse Trait::<_, _>::foo::<'_, '_, '_, _, _, _,> as foo5; + //~^ ERROR: trait takes 3 generic arguments but 0 generic arguments were supplied + //~| ERROR: method takes 3 generic arguments but 5 generic arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<'_, '_>::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: method takes 3 generic arguments but 6 generic arguments were supplied [E0107] + //~| ERROR: method takes 1 lifetime argument but 3 lifetime arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo::<_, '_, _, _> as foo7; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: wrong infer used: expected '_, found: _ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<'static, 'static, (), 123, ()>::foo::<'_, '_, '_, '_> as foo8; + //~^ ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<'static, 'static, _, _, _>::foo::<_> as foo9; + //~^ ERROR: method takes 3 generic arguments but 0 generic arguments were supplied + //~| ERROR: wrong infer used: expected '_, found: _ + + reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + //~^ ERROR: trait takes 3 generic arguments but 7 generic arguments were supplied [E0107] + //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied [E0107] + //~| ERROR: method takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: struct takes 0 lifetime arguments but 1 lifetime argument was supplied [E0107] + //~| ERROR: struct takes at least 1 generic argument but 0 generic arguments were supplied [E0107] + + reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + //~^ ERROR: trait takes 2 lifetime arguments but 5 lifetime arguments were supplied [E0107] + //~| ERROR: method takes 1 lifetime argument but 0 lifetime arguments were supplied [E0107] + //~| ERROR: method takes 3 generic arguments but 4 generic arguments were supplied [E0107] + //~| ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121] + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + //~| ERROR: wrong infer used: expected _, found: '_ + + reuse Trait::<'static, 'static, _>::foo::<'____, ___, _, ___> as foo12; + //~^ ERROR: cannot find type `___` in this scope + //~| ERROR: cannot find type `___` in this scope + //~| ERROR: use of undeclared lifetime name `'____` + //~| ERROR: trait takes 3 generic arguments but 1 generic argument was supplied + } +} + +mod trait_impl_to_free { + pub trait Trait<'a, 'b, X, const C: usize, Y> { + fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self) {} + } + + struct S; + impl<'a, 'b, X, const C: usize, Y> Trait<'a, 'b, X, C, Y> for S {} + + mod to_reuse { + pub fn foo(_: ()) {} + } + + struct F1(S); + impl<'a, 'b, X, const C: usize, Y> Trait<'a, 'b, X, C, Y> for F1 { + reuse to_reuse::foo::<_, _, _> { self.0 } + //~^ ERROR: mismatched types + } + + struct F2(S); + impl<'a, 'b, X, const C: usize, Y> Trait<'a, 'b, X, C, Y> for F2 { + reuse to_reuse::foo { self.0 } + //~^ ERROR: mismatched types + //~| ERROR: function takes 0 lifetime arguments but 1 lifetime argument was supplied + } + + struct F3(S); + impl<'a, 'b, X, const C: usize, Y> Trait<'a, 'b, X, C, Y> for F3 { + reuse to_reuse::foo::<(), 123, ()> { self.0 } + //~^ ERROR: mismatched types + } +} + +fn main() {} diff --git a/tests/ui/delegation/generics/infers.stderr b/tests/ui/delegation/generics/infers.stderr new file mode 100644 index 0000000000000..1ab3ef232832e --- /dev/null +++ b/tests/ui/delegation/generics/infers.stderr @@ -0,0 +1,1296 @@ +error: lifetimes must be followed by `+` to form a trait object type + --> $DIR/infers.rs:54:21 + | +LL | reuse foo::('_, _, _, _) as bar; + | ^^ + | +help: consider adding a trait bound after the potential lifetime bound + | +LL | reuse foo::('_ + /* Trait */, _, _, _) as bar; + | +++++++++++++ + +error[E0261]: use of undeclared lifetime name `'____` + --> $DIR/infers.rs:123:17 + | +LL | reuse foo::<'____, ___, _, ___> as foo12; + | ^^^^^ undeclared lifetime + | +help: consider introducing lifetime `'____` here + | +LL | reuse foo'____, ::<'____, ___, _, ___> as foo12; + | ++++++ + +error[E0261]: use of undeclared lifetime name `'____` + --> $DIR/infers.rs:195:28 + | +LL | reuse Trait::foo::<'____, ___, _, ___> as foo12; + | ^^^^^ undeclared lifetime + | +help: consider introducing lifetime `'____` here + | +LL | reuse Trait::foo'____, ::<'____, ___, _, ___> as foo12; + | ++++++ + +error[E0261]: use of undeclared lifetime name `'____` + --> $DIR/infers.rs:316:51 + | +LL | reuse Trait::<'static, 'static, _>::foo::<'____, ___, _, ___> as foo12; + | ^^^^^ undeclared lifetime + | +help: consider introducing lifetime `'____` here + | +LL | reuse Trait::<'static, 'static, _>::foo'____, ::<'____, ___, _, ___> as foo12; + | ++++++ + +error[E0425]: cannot find type `___` in this scope + --> $DIR/infers.rs:123:24 + | +LL | reuse foo::<'____, ___, _, ___> as foo12; + | ^^^ not found in this scope + +error[E0425]: cannot find type `___` in this scope + --> $DIR/infers.rs:123:32 + | +LL | reuse foo::<'____, ___, _, ___> as foo12; + | ^^^ not found in this scope + +error[E0425]: cannot find type `unresolved_` in this scope + --> $DIR/infers.rs:132:21 + | +LL | reuse foo::<'_, unresolved_, _, _> as foo14; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find type `___` in this scope + --> $DIR/infers.rs:195:35 + | +LL | reuse Trait::foo::<'____, ___, _, ___> as foo12; + | ^^^ not found in this scope + +error[E0425]: cannot find type `___` in this scope + --> $DIR/infers.rs:195:43 + | +LL | reuse Trait::foo::<'____, ___, _, ___> as foo12; + | ^^^ not found in this scope + +error[E0425]: cannot find type `unresolved_` in this scope + --> $DIR/infers.rs:204:32 + | +LL | reuse Trait::foo::<'_, unresolved_, _, _> as foo14; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find type `___` in this scope + --> $DIR/infers.rs:316:58 + | +LL | reuse Trait::<'static, 'static, _>::foo::<'____, ___, _, ___> as foo12; + | ^^^ not found in this scope + +error[E0425]: cannot find type `___` in this scope + --> $DIR/infers.rs:316:66 + | +LL | reuse Trait::<'static, 'static, _>::foo::<'____, ___, _, ___> as foo12; + | ^^^ not found in this scope + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:11:21 + | +LL | reuse foo::<_, '_, '_, '_> as bar; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:11:24 + | +LL | reuse foo::<_, '_, '_, '_> as bar; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:11:28 + | +LL | reuse foo::<_, '_, '_, '_> as bar; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:11:32 + | +LL | reuse foo::<_, '_, '_, '_> as bar; + | ^^ + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/infers.rs:54:15 + | +LL | reuse foo::('_, _, _, _) as bar; + | ^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + | +help: use angle brackets instead + | +LL - reuse foo::('_, _, _, _) as bar; +LL + reuse foo::<'_, _, _, _> as bar; + | + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:86:21 + | +LL | reuse foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:86:25 + | +LL | reuse foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:91:17 + | +LL | reuse foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:91:26 + | +LL | reuse foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:97:17 + | +LL | reuse foo::<_, '_, _, _> as foo7; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:97:20 + | +LL | reuse foo::<_, '_, _, _> as foo7; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:101:21 + | +LL | reuse foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:101:25 + | +LL | reuse foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:101:29 + | +LL | reuse foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:106:17 + | +LL | reuse foo::<_> as foo9; + | ^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:135:17 + | +LL | reuse foo::<_, _, _> as foo15; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:158:32 + | +LL | reuse Trait::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:158:36 + | +LL | reuse Trait::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:163:28 + | +LL | reuse Trait::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:163:37 + | +LL | reuse Trait::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:169:28 + | +LL | reuse Trait::foo::<_, '_, _, _> as foo7; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:169:31 + | +LL | reuse Trait::foo::<_, '_, _, _> as foo7; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:173:32 + | +LL | reuse Trait::foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:173:36 + | +LL | reuse Trait::foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:173:40 + | +LL | reuse Trait::foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:178:28 + | +LL | reuse Trait::foo::<_> as foo9; + | ^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:207:28 + | +LL | reuse Trait::foo::<_, _, _> as foo15; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:218:34 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo as foo3; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:226:23 + | +LL | reuse Trait::<_, _>::foo as foo5; + | ^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:226:26 + | +LL | reuse Trait::<_, _>::foo as foo5; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:244:41 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_, '_>::foo as foo11; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:244:44 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_, '_>::foo as foo11; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:244:48 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_, '_>::foo as foo11; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:260:34 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo::<'static, String, _, _> as foo3; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:268:23 + | +LL | reuse Trait::<_, _>::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:268:26 + | +LL | reuse Trait::<_, _>::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:268:40 + | +LL | reuse Trait::<_, _>::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:268:44 + | +LL | reuse Trait::<_, _>::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:276:38 + | +LL | reuse Trait::<'_, '_>::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:276:47 + | +LL | reuse Trait::<'_, '_>::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:283:64 + | +LL | reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo::<_, '_, _, _> as foo7; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:283:67 + | +LL | reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo::<_, '_, _, _> as foo7; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:289:65 + | +LL | reuse Trait::<'static, 'static, (), 123, ()>::foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:289:69 + | +LL | reuse Trait::<'static, 'static, (), 123, ()>::foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:289:73 + | +LL | reuse Trait::<'static, 'static, (), 123, ()>::foo::<'_, '_, '_, '_> as foo8; + | ^^ + +error: wrong infer used: expected '_, found: _ + --> $DIR/infers.rs:294:57 + | +LL | reuse Trait::<'static, 'static, _, _, _>::foo::<_> as foo9; + | ^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:306:41 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:306:44 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^^ + +error: wrong infer used: expected _, found: '_ + --> $DIR/infers.rs:306:48 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^^ + +error[E0107]: function takes 1 lifetime argument but 2 lifetime arguments were supplied + --> $DIR/infers.rs:44:15 + | +LL | reuse foo::<'_, '_> as foo2; + | ^^^--------- help: remove the lifetime argument + | | + | expected 1 lifetime argument + | +note: function defined here, with 1 lifetime parameter: `'c` + --> $DIR/infers.rs:38:12 + | +LL | fn foo<'a, 'b, 'c: 'c, 'd>(_: &'a &'b &'c &'d ()) {} + | ^^^ -- + +error[E0107]: function takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/infers.rs:54:15 + | +LL | reuse foo::('_, _, _, _) as bar; + | ^^^ expected 1 lifetime argument + | +note: function defined here, with 1 lifetime parameter: `'b` + --> $DIR/infers.rs:52:12 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ -- +help: add missing lifetime argument + | +LL | reuse foo::('b, '_, _, _, _) as bar; + | +++ + +error[E0107]: function takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:54:15 + | +LL | reuse foo::('_, _, _, _) as bar; + | ^^^ --- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: function defined here, with 3 generic parameters: `X`, `M`, `Y` + --> $DIR/infers.rs:52:12 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ - -------------- - + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:54:15 + | +LL | reuse foo::('_, _, _, _) as bar; + | ^^^ + +error[E0224]: at least one trait is required for an object type + --> $DIR/infers.rs:54:21 + | +LL | reuse foo::('_, _, _, _) as bar; + | ^^ + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:54:25 + | +LL | reuse foo::('_, _, _, _) as bar; + | ^ not allowed in type signatures + +error[E0107]: function takes 3 generic arguments but 5 generic arguments were supplied + --> $DIR/infers.rs:86:11 + | +LL | reuse foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^^---------------------- help: remove the unnecessary generic arguments + | | + | expected 3 generic arguments + | +note: function defined here, with 3 generic parameters: `X`, `M`, `Y` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ - -------------- - + +error[E0107]: function takes 1 lifetime argument but 3 lifetime arguments were supplied + --> $DIR/infers.rs:91:11 + | +LL | reuse foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^^---------------------- help: remove the lifetime arguments + | | + | expected 1 lifetime argument + | +note: function defined here, with 1 lifetime parameter: `'b` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ -- + +error[E0107]: function takes 3 generic arguments but 6 generic arguments were supplied + --> $DIR/infers.rs:91:11 + | +LL | reuse foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^^------------------------------- help: remove the unnecessary generic arguments + | | + | expected 3 generic arguments + | +note: function defined here, with 3 generic parameters: `X`, `M`, `Y` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ - -------------- - + +error[E0107]: function takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/infers.rs:106:11 + | +LL | reuse foo::<_> as foo9; + | ^^^ expected 3 generic arguments + | +note: function defined here, with 3 generic parameters: `X`, `M`, `Y` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ - -------------- - +help: add missing generic arguments + | +LL | reuse fooX, M, Y::<_> as foo9; + | +++++++ + +error[E0107]: function takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/infers.rs:110:11 + | +LL | reuse foo::, _, _, ()> as foo10; + | ^^^ expected 1 lifetime argument + | +note: function defined here, with 1 lifetime parameter: `'b` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ -- +help: add missing lifetime argument + | +LL | reuse foo::<'b, Vec<'_>, _, _, ()> as foo10; + | +++ + +error[E0107]: function takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:110:11 + | +LL | reuse foo::, _, _, ()> as foo10; + | ^^^-------------------- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: function defined here, with 3 generic parameters: `X`, `M`, `Y` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ - -------------- - + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:110:11 + | +LL | reuse foo::, _, _, ()> as foo10; + | ^^^ + +error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/infers.rs:110:17 + | +LL | reuse foo::, _, _, ()> as foo10; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 lifetime arguments + +error[E0107]: struct takes at least 1 generic argument but 0 generic arguments were supplied + --> $DIR/infers.rs:110:17 + | +LL | reuse foo::, _, _, ()> as foo10; + | ^^^ expected at least 1 generic argument + | +help: add missing generic argument + | +LL | reuse foo::, _, _, ()> as foo10; + | +++ + +error[E0107]: function takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/infers.rs:117:11 + | +LL | reuse foo::, _, _, ()> as foo11; + | ^^^ expected 1 lifetime argument + | +note: function defined here, with 1 lifetime parameter: `'b` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ -- +help: add missing lifetime argument + | +LL | reuse foo::<'b, Vec<_>, _, _, ()> as foo11; + | +++ + +error[E0107]: function takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:117:11 + | +LL | reuse foo::, _, _, ()> as foo11; + | ^^^------------------- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: function defined here, with 3 generic parameters: `X`, `M`, `Y` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ - -------------- - + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:117:11 + | +LL | reuse foo::, _, _, ()> as foo11; + | ^^^ + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:117:21 + | +LL | reuse foo::, _, _, ()> as foo11; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:128:25 + | +LL | reuse foo::<'_, Vec<_>, Vec>, _> as foo13; + | ^ not allowed in type signatures + +error[E0747]: type provided when a constant was expected + --> $DIR/infers.rs:128:29 + | +LL | reuse foo::<'_, Vec<_>, Vec>, _> as foo13; + | ^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | reuse foo::<'_, Vec<_>, { Vec> }, _> as foo13; + | + + + +error[E0107]: function takes 3 generic arguments but 2 generic arguments were supplied + --> $DIR/infers.rs:135:11 + | +LL | reuse foo::<_, _, _> as foo15; + | ^^^ + | | + | expected 3 generic arguments + | supplied 2 generic arguments + | +note: function defined here, with 3 generic parameters: `X`, `M`, `Y` + --> $DIR/infers.rs:79:8 + | +LL | fn foo<'a, 'b: 'b, 'c, X, const M: usize, Y>(_: &'a &'b &'c ()) {} + | ^^^ - -------------- - +help: add missing generic argument + | +LL | reuse fooY::<_, _, _> as foo15; + | + + +error[E0207]: the type parameter `Some` is not constrained by the impl trait, self type, or predicates + --> $DIR/infers.rs:146:18 + | +LL | impl<'a, 'b, Some, Params, X, const C: usize, Y> Trait<'a, 'b, X, C, Y> for X {} + | ^^^^ unconstrained type parameter + +error[E0207]: the type parameter `Params` is not constrained by the impl trait, self type, or predicates + --> $DIR/infers.rs:146:24 + | +LL | impl<'a, 'b, Some, Params, X, const C: usize, Y> Trait<'a, 'b, X, C, Y> for X {} + | ^^^^^^ unconstrained type parameter + +error[E0107]: method takes 3 generic arguments but 5 generic arguments were supplied + --> $DIR/infers.rs:158:22 + | +LL | reuse Trait::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^^---------------------- help: remove the unnecessary generic arguments + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error[E0107]: method takes 1 lifetime argument but 3 lifetime arguments were supplied + --> $DIR/infers.rs:163:22 + | +LL | reuse Trait::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^^---------------------- help: remove the lifetime arguments + | | + | expected 1 lifetime argument + | +note: method defined here, with 1 lifetime parameter: `'bb` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ --- + +error[E0107]: method takes 3 generic arguments but 6 generic arguments were supplied + --> $DIR/infers.rs:163:22 + | +LL | reuse Trait::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^^------------------------------- help: remove the unnecessary generic arguments + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error[E0107]: method takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/infers.rs:178:22 + | +LL | reuse Trait::foo::<_> as foo9; + | ^^^ expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- +help: add missing generic arguments + | +LL | reuse Trait::fooXX, M, YY::<_> as foo9; + | +++++++++ + +error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/infers.rs:182:22 + | +LL | reuse Trait::foo::, _, _, ()> as foo10; + | ^^^ expected 1 lifetime argument + | +note: method defined here, with 1 lifetime parameter: `'bb` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ --- +help: add missing lifetime argument + | +LL | reuse Trait::foo::<'a, Vec<'_>, _, _, ()> as foo10; + | +++ + +error[E0107]: method takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:182:22 + | +LL | reuse Trait::foo::, _, _, ()> as foo10; + | ^^^-------------------- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:182:22 + | +LL | reuse Trait::foo::, _, _, ()> as foo10; + | ^^^ + +error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/infers.rs:182:28 + | +LL | reuse Trait::foo::, _, _, ()> as foo10; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 lifetime arguments + +error[E0107]: struct takes at least 1 generic argument but 0 generic arguments were supplied + --> $DIR/infers.rs:182:28 + | +LL | reuse Trait::foo::, _, _, ()> as foo10; + | ^^^ expected at least 1 generic argument + | +help: add missing generic argument + | +LL | reuse Trait::foo::, _, _, ()> as foo10; + | +++ + +error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/infers.rs:189:22 + | +LL | reuse Trait::foo::, _, _, ()> as foo11; + | ^^^ expected 1 lifetime argument + | +note: method defined here, with 1 lifetime parameter: `'bb` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ --- +help: add missing lifetime argument + | +LL | reuse Trait::foo::<'a, Vec<_>, _, _, ()> as foo11; + | +++ + +error[E0107]: method takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:189:22 + | +LL | reuse Trait::foo::, _, _, ()> as foo11; + | ^^^------------------- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:189:22 + | +LL | reuse Trait::foo::, _, _, ()> as foo11; + | ^^^ + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:189:32 + | +LL | reuse Trait::foo::, _, _, ()> as foo11; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:200:36 + | +LL | reuse Trait::foo::<'_, Vec<_>, Vec>, _> as foo13; + | ^ not allowed in type signatures + +error[E0747]: type provided when a constant was expected + --> $DIR/infers.rs:200:40 + | +LL | reuse Trait::foo::<'_, Vec<_>, Vec>, _> as foo13; + | ^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | reuse Trait::foo::<'_, Vec<_>, { Vec> }, _> as foo13; + | + + + +error[E0107]: method takes 3 generic arguments but 2 generic arguments were supplied + --> $DIR/infers.rs:207:22 + | +LL | reuse Trait::foo::<_, _, _> as foo15; + | ^^^ + | | + | expected 3 generic arguments + | supplied 2 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- +help: add missing generic argument + | +LL | reuse Trait::fooYY::<_, _, _> as foo15; + | ++ + +error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/infers.rs:218:15 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo as foo3; + | ^^^^^ --- supplied 1 lifetime argument + | | + | expected 2 lifetime arguments + | +note: trait defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ -- -- +help: add missing lifetime argument + | +LL | reuse Trait::<'_, (), _, '_, _>::foo, 'a as foo3; + | ++++ + +error[E0107]: trait takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:218:15 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo as foo3; + | ^^^^^ --- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:218:15 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo as foo3; + | ^^^^^ + +error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/infers.rs:226:15 + | +LL | reuse Trait::<_, _>::foo as foo5; + | ^^^^^ expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - +help: add missing generic arguments + | +LL | reuse Trait::<_, _>::foo, X, C, Y as foo5; + | +++++++++ + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:231:15 + | +LL | reuse Trait::<'_, '_>::foo as foo6; + | ^^^^^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:234:35 + | +LL | reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo as foo7; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:234:52 + | +LL | reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo as foo7; + | ^ not allowed in type signatures + +error[E0107]: trait takes 3 generic arguments but 7 generic arguments were supplied + --> $DIR/infers.rs:241:15 + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo as foo10; + | ^^^^^ expected 3 generic arguments ------- help: remove the unnecessary generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - + +error[E0107]: trait takes 2 lifetime arguments but 6 lifetime arguments were supplied + --> $DIR/infers.rs:244:15 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_, '_>::foo as foo11; + | ^^^^^ --------------------------- help: remove the lifetime arguments + | | + | expected 2 lifetime arguments + | +note: trait defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ -- -- + +error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/infers.rs:250:15 + | +LL | reuse Trait::<'static, 'static, _>::foo as foo12; + | ^^^^^ --- supplied 1 generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - +help: add missing generic arguments + | +LL | reuse Trait::<'static, 'static, _>::foo, C, Y as foo12; + | ++++++ + +error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/infers.rs:260:15 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo::<'static, String, _, _> as foo3; + | ^^^^^ --- supplied 1 lifetime argument + | | + | expected 2 lifetime arguments + | +note: trait defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ -- -- +help: add missing lifetime argument + | +LL | reuse Trait::<'_, (), _, '_, _>::foo, 'a::<'static, String, _, _> as foo3; + | ++++ + +error[E0107]: trait takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:260:15 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo::<'static, String, _, _> as foo3; + | ^^^^^ --- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:260:15 + | +LL | reuse Trait::<'_, (), _, '_, _>::foo::<'static, String, _, _> as foo3; + | ^^^^^ + +error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/infers.rs:268:15 + | +LL | reuse Trait::<_, _>::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^^^^ expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - +help: add missing generic arguments + | +LL | reuse Trait::<_, _>::foo, X, C, Y::<'_, '_, '_, _, _, _,> as foo5; + | +++++++++ + +error[E0107]: method takes 3 generic arguments but 5 generic arguments were supplied + --> $DIR/infers.rs:268:30 + | +LL | reuse Trait::<_, _>::foo::<'_, '_, '_, _, _, _,> as foo5; + | ^^^---------------------- help: remove the unnecessary generic arguments + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:276:15 + | +LL | reuse Trait::<'_, '_>::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^^^^ not allowed in type signatures + +error[E0107]: method takes 1 lifetime argument but 3 lifetime arguments were supplied + --> $DIR/infers.rs:276:32 + | +LL | reuse Trait::<'_, '_>::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^^---------------------- help: remove the lifetime arguments + | | + | expected 1 lifetime argument + | +note: method defined here, with 1 lifetime parameter: `'bb` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ --- + +error[E0107]: method takes 3 generic arguments but 6 generic arguments were supplied + --> $DIR/infers.rs:276:32 + | +LL | reuse Trait::<'_, '_>::foo::<_, _, _, '_, '_, '_, _, _, _,> as foo6; + | ^^^------------------------------- help: remove the unnecessary generic arguments + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:283:35 + | +LL | reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo::<_, '_, _, _> as foo7; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:283:52 + | +LL | reuse Trait::<'_, '_, Vec<_>, 123, Vec>>::foo::<_, '_, _, _> as foo7; + | ^ not allowed in type signatures + +error[E0107]: method takes 3 generic arguments but 0 generic arguments were supplied + --> $DIR/infers.rs:294:51 + | +LL | reuse Trait::<'static, 'static, _, _, _>::foo::<_> as foo9; + | ^^^ expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- +help: add missing generic arguments + | +LL | reuse Trait::<'static, 'static, _, _, _>::fooXX, M, YY::<_> as foo9; + | +++++++++ + +error[E0107]: trait takes 3 generic arguments but 7 generic arguments were supplied + --> $DIR/infers.rs:298:15 + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + | ^^^^^ expected 3 generic arguments ------- help: remove the unnecessary generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - + +error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/infers.rs:298:63 + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + | ^^^ expected 1 lifetime argument + | +note: method defined here, with 1 lifetime parameter: `'bb` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ --- +help: add missing lifetime argument + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::<'bb, Vec<'_>, _, _, ()> as foo10; + | ++++ + +error[E0107]: method takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:298:63 + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + | ^^^-------------------- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:298:63 + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + | ^^^ + +error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/infers.rs:298:69 + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 lifetime arguments + +error[E0107]: struct takes at least 1 generic argument but 0 generic arguments were supplied + --> $DIR/infers.rs:298:69 + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + | ^^^ expected at least 1 generic argument + | +help: add missing generic argument + | +LL | reuse Trait::<'static, 'static, _, _, _, _, _, _, _>::foo::, _, _, ()> as foo10; + | +++ + +error[E0107]: trait takes 2 lifetime arguments but 5 lifetime arguments were supplied + --> $DIR/infers.rs:306:15 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^^^^^ ----------------------- help: remove the lifetime arguments + | | + | expected 2 lifetime arguments + | +note: trait defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ -- -- + +error[E0107]: method takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/infers.rs:306:65 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^^^ expected 1 lifetime argument + | +note: method defined here, with 1 lifetime parameter: `'bb` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ --- +help: add missing lifetime argument + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::<'bb, Vec<_>, _, _, ()> as foo11; + | ++++ + +error[E0107]: method takes 3 generic arguments but 4 generic arguments were supplied + --> $DIR/infers.rs:306:65 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^^^------------------- help: remove the unnecessary generic argument + | | + | expected 3 generic arguments + | +note: method defined here, with 3 generic parameters: `XX`, `M`, `YY` + --> $DIR/infers.rs:142:12 + | +LL | fn foo<'aa, 'bb: 'bb, 'cc, XX, const M: usize, YY>(&self, _: &'aa &'b &'cc ()) {} + | ^^^ -- -------------- -- + +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/infers.rs:306:65 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^^^ + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/infers.rs:306:75 + | +LL | reuse Trait::<'static, 'static, '_,'_, '_, '_, '_, '_>::foo::, _, _, ()> as foo11; + | ^ not allowed in type signatures + +error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied + --> $DIR/infers.rs:316:15 + | +LL | reuse Trait::<'static, 'static, _>::foo::<'____, ___, _, ___> as foo12; + | ^^^^^ --- supplied 1 generic argument + | | + | expected 3 generic arguments + | +note: trait defined here, with 3 generic parameters: `X`, `C`, `Y` + --> $DIR/infers.rs:141:15 + | +LL | pub trait Trait<'a, 'b, X, const C: usize, Y> { + | ^^^^^ - -------------- - +help: add missing generic arguments + | +LL | reuse Trait::<'static, 'static, _>::foo, C, Y::<'____, ___, _, ___> as foo12; + | ++++++ + +error[E0308]: mismatched types + --> $DIR/infers.rs:338:42 + | +LL | reuse to_reuse::foo::<_, _, _> { self.0 } + | --- ^^^^^^ expected `()`, found `S` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/infers.rs:333:16 + | +LL | pub fn foo(_: ()) {} + | ^^^ ----- + +error[E0107]: function takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/infers.rs:344:25 + | +LL | reuse to_reuse::foo { self.0 } + | ^^^ + | | + | expected 0 lifetime arguments + | help: remove the lifetime argument + | +note: function defined here, with 0 lifetime parameters + --> $DIR/infers.rs:333:16 + | +LL | pub fn foo(_: ()) {} + | ^^^ + +error[E0308]: mismatched types + --> $DIR/infers.rs:344:31 + | +LL | reuse to_reuse::foo { self.0 } + | --- ^^^^^^ expected `()`, found `S` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/infers.rs:333:16 + | +LL | pub fn foo(_: ()) {} + | ^^^ ----- + +error[E0308]: mismatched types + --> $DIR/infers.rs:351:46 + | +LL | reuse to_reuse::foo::<(), 123, ()> { self.0 } + | --- ^^^^^^ expected `()`, found `S` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/infers.rs:333:16 + | +LL | pub fn foo(_: ()) {} + | ^^^ ----- + +error: aborting due to 138 previous errors + +Some errors have detailed explanations: E0107, E0121, E0207, E0214, E0224, E0261, E0308, E0425, E0747. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs b/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs index 4073e5ce88607..7b33e1d16eadf 100644 --- a/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs +++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs @@ -26,6 +26,7 @@ mod test_1 { reuse to_reuse::bar1; //~^ ERROR: function takes 0 generic arguments but 3 generic arguments were supplied + //~| ERROR: function takes 0 lifetime arguments but 2 lifetime arguments were supplied reuse to_reuse::bar2; //~^ ERROR: type annotations needed @@ -59,8 +60,10 @@ mod test_2 { impl Trait for X { reuse ::bar; //~^ ERROR: missing generics for trait + //~| ERROR: associated function takes 1 lifetime argument but 2 lifetime arguments were supplied reuse >::bar as bar1; + //~^ ERROR: associated function takes 1 lifetime argument but 2 lifetime arguments were supplied reuse >::bar::<'static, u32, u32, 1> as bar2; @@ -94,9 +97,11 @@ mod test_3 { impl Trait for X { reuse >::bar; //~^ ERROR: associated function takes 0 generic arguments but 3 generic arguments were supplied + //~| ERROR: associated function takes 0 lifetime arguments but 2 lifetime arguments were supplied reuse >::bar as bar1; //~^ ERROR: associated function takes 0 generic arguments but 3 generic arguments were supplied + //~| ERROR: associated function takes 0 lifetime arguments but 2 lifetime arguments were supplied reuse >::foo as bar2; //~^ ERROR: type annotations needed diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr index 09281768bbf73..931b61ef0ca85 100644 --- a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr +++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr @@ -13,11 +13,29 @@ note: function defined here, with at most 2 generic parameters: `A`, `B` LL | pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} | ^^^ - - +error[E0107]: function takes 0 lifetime arguments but 2 lifetime arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:27:25 + | +LL | reuse to_reuse::bar1; + | ^^^^ + | | + | expected 0 lifetime arguments + | help: remove the lifetime arguments + | +note: function defined here, with 0 lifetime parameters + --> $DIR/trait-impl-wrong-args-count.rs:7:16 + | +LL | pub fn bar1(x: &super::XX) {} + | ^^^^ + error[E0107]: function takes 0 generic arguments but 3 generic arguments were supplied --> $DIR/trait-impl-wrong-args-count.rs:27:25 | LL | reuse to_reuse::bar1; - | ^^^^ expected 0 generic arguments + | ^^^^ + | | + | expected 0 generic arguments + | help: remove the unnecessary generic arguments | note: function defined here, with 0 generic parameters --> $DIR/trait-impl-wrong-args-count.rs:7:16 @@ -26,7 +44,7 @@ LL | pub fn bar1(x: &super::XX) {} | ^^^^ error[E0284]: type annotations needed - --> $DIR/trait-impl-wrong-args-count.rs:30:25 + --> $DIR/trait-impl-wrong-args-count.rs:31:25 | LL | reuse to_reuse::bar2; | ^^^^ cannot infer the value of the const parameter `X` declared on the function `bar2` @@ -42,7 +60,7 @@ LL | reuse to_reuse::bar2::; | ++++++++++++++++++++++++++ error[E0284]: type annotations needed - --> $DIR/trait-impl-wrong-args-count.rs:30:25 + --> $DIR/trait-impl-wrong-args-count.rs:31:25 | LL | reuse to_reuse::bar2; | ^^^^ cannot infer the value of the const parameter `Y` declared on the function `bar2` @@ -58,13 +76,13 @@ LL | reuse to_reuse::bar2::; | ++++++++++++++++++++++++++ error[E0107]: missing generics for trait `test_2::Trait1` - --> $DIR/trait-impl-wrong-args-count.rs:60:21 + --> $DIR/trait-impl-wrong-args-count.rs:61:21 | LL | reuse ::bar; | ^^^^^^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/trait-impl-wrong-args-count.rs:51:11 + --> $DIR/trait-impl-wrong-args-count.rs:52:11 | LL | trait Trait1 { | ^^^^^^ - - @@ -73,14 +91,44 @@ help: add missing generic arguments LL | reuse >::bar; | ++++++ +error[E0107]: associated function takes 1 lifetime argument but 2 lifetime arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:61:30 + | +LL | reuse ::bar; + | ^^^ + | | + | expected 1 lifetime argument + | help: remove the lifetime argument + | +note: associated function defined here, with 1 lifetime parameter: `'x` + --> $DIR/trait-impl-wrong-args-count.rs:53:12 + | +LL | fn bar<'x: 'x, AA, BB, const NN: usize>() {} + | ^^^ -- + +error[E0107]: associated function takes 1 lifetime argument but 2 lifetime arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:65:44 + | +LL | reuse >::bar as bar1; + | ^^^ + | | + | expected 1 lifetime argument + | help: remove the lifetime argument + | +note: associated function defined here, with 1 lifetime parameter: `'x` + --> $DIR/trait-impl-wrong-args-count.rs:53:12 + | +LL | fn bar<'x: 'x, AA, BB, const NN: usize>() {} + | ^^^ -- + error[E0107]: missing generics for trait `test_2::Trait1` - --> $DIR/trait-impl-wrong-args-count.rs:67:21 + --> $DIR/trait-impl-wrong-args-count.rs:70:21 | LL | reuse ::bar::<'static, u32, u32, 1> as bar3; | ^^^^^^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/trait-impl-wrong-args-count.rs:51:11 + --> $DIR/trait-impl-wrong-args-count.rs:52:11 | LL | trait Trait1 { | ^^^^^^ - - @@ -90,13 +138,13 @@ LL | reuse >::bar::<'static, u32, u32, 1> as bar3; | ++++++ error[E0107]: missing generics for trait `test_2::Trait1` - --> $DIR/trait-impl-wrong-args-count.rs:70:21 + --> $DIR/trait-impl-wrong-args-count.rs:73:21 | LL | reuse ::bar as bar4; | ^^^^^^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/trait-impl-wrong-args-count.rs:51:11 + --> $DIR/trait-impl-wrong-args-count.rs:52:11 | LL | trait Trait1 { | ^^^^^^ - - @@ -105,38 +153,74 @@ help: add missing generic arguments LL | reuse >::bar as bar4; | ++++++ +error[E0107]: associated function takes 0 lifetime arguments but 2 lifetime arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:98:40 + | +LL | reuse >::bar; + | ^^^ + | | + | expected 0 lifetime arguments + | help: remove the lifetime arguments + | +note: associated function defined here, with 0 lifetime parameters + --> $DIR/trait-impl-wrong-args-count.rs:89:12 + | +LL | fn bar() {} + | ^^^ + error[E0107]: associated function takes 0 generic arguments but 3 generic arguments were supplied - --> $DIR/trait-impl-wrong-args-count.rs:95:40 + --> $DIR/trait-impl-wrong-args-count.rs:98:40 | LL | reuse >::bar; - | ^^^ expected 0 generic arguments + | ^^^ + | | + | expected 0 generic arguments + | help: remove the unnecessary generic arguments | note: associated function defined here, with 0 generic parameters - --> $DIR/trait-impl-wrong-args-count.rs:86:12 + --> $DIR/trait-impl-wrong-args-count.rs:89:12 + | +LL | fn bar() {} + | ^^^ + +error[E0107]: associated function takes 0 lifetime arguments but 2 lifetime arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:102:40 + | +LL | reuse >::bar as bar1; + | ^^^ + | | + | expected 0 lifetime arguments + | help: remove the lifetime arguments + | +note: associated function defined here, with 0 lifetime parameters + --> $DIR/trait-impl-wrong-args-count.rs:89:12 | LL | fn bar() {} | ^^^ error[E0107]: associated function takes 0 generic arguments but 3 generic arguments were supplied - --> $DIR/trait-impl-wrong-args-count.rs:98:40 + --> $DIR/trait-impl-wrong-args-count.rs:102:40 | LL | reuse >::bar as bar1; - | ^^^ expected 0 generic arguments + | ^^^ + | | + | expected 0 generic arguments + | help: remove the unnecessary generic arguments | note: associated function defined here, with 0 generic parameters - --> $DIR/trait-impl-wrong-args-count.rs:86:12 + --> $DIR/trait-impl-wrong-args-count.rs:89:12 | LL | fn bar() {} | ^^^ error[E0282]: type annotations needed - --> $DIR/trait-impl-wrong-args-count.rs:101:40 + --> $DIR/trait-impl-wrong-args-count.rs:106:40 | LL | reuse >::foo as bar2; | ^^^ cannot infer type of the type parameter `X` declared on the associated function `foo` error[E0107]: associated function takes at most 2 generic arguments but 3 generic arguments were supplied - --> $DIR/trait-impl-wrong-args-count.rs:104:40 + --> $DIR/trait-impl-wrong-args-count.rs:109:40 | LL | reuse >::foo as bar3; | ^^^ @@ -145,12 +229,12 @@ LL | reuse >::foo as bar3; | help: remove the unnecessary generic argument | note: associated function defined here, with at most 2 generic parameters: `X`, `Y` - --> $DIR/trait-impl-wrong-args-count.rs:87:12 + --> $DIR/trait-impl-wrong-args-count.rs:90:12 | LL | fn foo() {} | ^^^ - - -error: aborting due to 11 previous errors +error: aborting due to 16 previous errors Some errors have detailed explanations: E0107, E0282, E0284. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.rs b/tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.rs index fad06b37ae416..1f97f7c652c35 100644 --- a/tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.rs +++ b/tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.rs @@ -1,3 +1,4 @@ +//@ check-pass //@ compile-flags: -Z deduplicate-diagnostics=yes #![feature(fn_delegation)] @@ -12,11 +13,8 @@ impl Trait for F {} struct S(F); impl S { reuse Trait::foo::<> { self.0 } - //~^ ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + reuse Trait::foo::<'_> as bar { self.0 } - //~^ ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature - //~| WARN: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } fn main() {} diff --git a/tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.stderr b/tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.stderr deleted file mode 100644 index 464b6a3a76819..0000000000000 --- a/tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/unelided-lifetime-in-sig-ice-156848.rs:14:18 - | -LL | reuse Trait::foo::<> { self.0 } - | ^^^ - -warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/unelided-lifetime-in-sig-ice-156848.rs:16:24 - | -LL | fn foo<'a: 'a>(&self) {} - | - the late bound lifetime parameter is introduced here -... -LL | reuse Trait::foo::<'_> as bar { self.0 } - | ^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #42868 - = note: `#[warn(late_bound_lifetime_arguments)]` (part of `#[warn(future_incompatible)]`) on by default - -error: inferred lifetimes are not allowed in delegations as we need to inherit signature - --> $DIR/unelided-lifetime-in-sig-ice-156848.rs:16:24 - | -LL | reuse Trait::foo::<'_> as bar { self.0 } - | ^^ - -error: aborting due to 2 previous errors; 1 warning emitted - diff --git a/tests/ui/delegation/self-ty-ice-156388.rs b/tests/ui/delegation/self-ty-ice-156388.rs index 542f56867b2b2..74cad01236375 100644 --- a/tests/ui/delegation/self-ty-ice-156388.rs +++ b/tests/ui/delegation/self-ty-ice-156388.rs @@ -1,8 +1,9 @@ //@ compile-flags: -Z deduplicate-diagnostics=yes +#![feature(const_trait_impl)] #![feature(fn_delegation)] reuse Default::default; -//~^ ERROR: delegation self type is not specified +//~^ ERROR: the trait bound `Self: [const] Default` is not satisfied fn main() {} diff --git a/tests/ui/delegation/self-ty-ice-156388.stderr b/tests/ui/delegation/self-ty-ice-156388.stderr index c2323cf1c6082..a311635db608a 100644 --- a/tests/ui/delegation/self-ty-ice-156388.stderr +++ b/tests/ui/delegation/self-ty-ice-156388.stderr @@ -1,10 +1,14 @@ -error: delegation self type is not specified - --> $DIR/self-ty-ice-156388.rs:5:16 +error[E0277]: the trait bound `Self: [const] Default` is not satisfied + --> $DIR/self-ty-ice-156388.rs:6:16 | LL | reuse Default::default; | ^^^^^^^ | - = help: consider explicitly specifying self type: `reuse ::function` +help: consider restricting type parameter `Self` with trait `Default` + | +LL | reuse Default::default [const] std::default::Default; + | +++++++++++++++++++++++++++++ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/target-expr.rs b/tests/ui/delegation/target-expr.rs index 14232d194a740..b4b3a31f437fc 100644 --- a/tests/ui/delegation/target-expr.rs +++ b/tests/ui/delegation/target-expr.rs @@ -15,7 +15,6 @@ fn foo(x: i32) -> i32 { x } fn bar(_: T) { reuse Trait::static_method { - //~^ ERROR: delegation self type is not specified let _ = T::Default(); //~^ ERROR can't use generic parameters from outer item } diff --git a/tests/ui/delegation/target-expr.stderr b/tests/ui/delegation/target-expr.stderr index 9126234a2c3cd..2ceefbf929b9f 100644 --- a/tests/ui/delegation/target-expr.stderr +++ b/tests/ui/delegation/target-expr.stderr @@ -1,18 +1,17 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/target-expr.rs:19:17 + --> $DIR/target-expr.rs:18:17 | LL | fn bar(_: T) { | - type parameter from outer item LL | reuse Trait::static_method { | ------------- generic parameter used in this inner delegated function -LL | LL | let _ = T::Default(); | ^ use of generic parameter from outer item | = note: nested items are independent from their parent item for everything except for privacy and name resolution error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/target-expr.rs:27:17 + --> $DIR/target-expr.rs:26:17 | LL | let x = y; | ^ @@ -20,7 +19,7 @@ LL | let x = y; = help: use the `|| { ... }` closure form instead error[E0424]: expected value, found module `self` - --> $DIR/target-expr.rs:34:5 + --> $DIR/target-expr.rs:33:5 | LL | fn main() { | ---- this function can't have a `self` parameter @@ -29,26 +28,18 @@ LL | self.0; | ^^^^ `self` value is a keyword only available in methods with a `self` parameter error[E0425]: cannot find value `x` in this scope - --> $DIR/target-expr.rs:36:13 + --> $DIR/target-expr.rs:35:13 | LL | let z = x; | ^ | help: the binding `x` is available in a different scope in the same function - --> $DIR/target-expr.rs:27:13 + --> $DIR/target-expr.rs:26:13 | LL | let x = y; | ^ -error: delegation self type is not specified - --> $DIR/target-expr.rs:17:18 - | -LL | reuse Trait::static_method { - | ^^^^^^^^^^^^^ - | - = help: consider explicitly specifying self type: `reuse ::function` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0401, E0424, E0425, E0434. For more information about an error, try `rustc --explain E0401`. diff --git a/tests/ui/delegation/unsupported.current.stderr b/tests/ui/delegation/unsupported.current.stderr index fdfd9251b4650..6cdd54e2e27fc 100644 --- a/tests/ui/delegation/unsupported.current.stderr +++ b/tests/ui/delegation/unsupported.current.stderr @@ -20,14 +20,6 @@ LL | reuse ToReuse::opaque_ret; = note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition = note: for more information, see and -error: delegation self type is not specified - --> $DIR/unsupported.rs:54:18 - | -LL | reuse Trait::foo; - | ^^^ - | - = help: consider explicitly specifying self type: `reuse ::function` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr index fdfd9251b4650..6cdd54e2e27fc 100644 --- a/tests/ui/delegation/unsupported.next.stderr +++ b/tests/ui/delegation/unsupported.next.stderr @@ -20,14 +20,6 @@ LL | reuse ToReuse::opaque_ret; = note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition = note: for more information, see and -error: delegation self type is not specified - --> $DIR/unsupported.rs:54:18 - | -LL | reuse Trait::foo; - | ^^^ - | - = help: consider explicitly specifying self type: `reuse ::function` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index 3349c4ec27ab1..3da1206b5b2df 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -52,7 +52,6 @@ mod effects { } reuse Trait::foo; - //~^ ERROR: delegation self type is not specified } fn main() {} From 699346d04f44b516d9e58343ab2df257f2d4fd53 Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 22 Jun 2026 23:57:57 +0200 Subject: [PATCH 101/116] move batch --- .../ui/{issues/issue-25497.rs => box/match-box-deref-codegen.rs} | 0 .../match-enum-range-metadata-misopt.rs} | 0 .../issue-25515.rs => drop/rc-trait-object-double-drop.rs} | 0 .../supertrait-with-self-in-type-arg.rs} | 0 .../supertrait-with-self-in-type-arg.stderr} | 0 .../issue-26217.rs => higher-ranked/forall-implies-static.rs} | 0 .../forall-implies-static.stderr} | 0 .../trait-bounds/infer-assoc-type-projection-type.rs} | 0 .../issue-25343.rs => label/label-in-closure-no-self-shadow.rs} | 0 .../issue-26237.rs => macros/non-function-call-in-macro.rs} | 0 .../non-function-call-in-macro.stderr} | 0 .../issue-2590.rs => moves/move-field-out-of-shared-self.rs} | 0 .../move-field-out-of-shared-self.stderr} | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-25497.rs => box/match-box-deref-codegen.rs} (100%) rename tests/ui/{issues/issue-26468.rs => codegen/match-enum-range-metadata-misopt.rs} (100%) rename tests/ui/{issues/issue-25515.rs => drop/rc-trait-object-double-drop.rs} (100%) rename tests/ui/{issues/issue-26056.rs => dyn-compatibility/supertrait-with-self-in-type-arg.rs} (100%) rename tests/ui/{issues/issue-26056.stderr => dyn-compatibility/supertrait-with-self-in-type-arg.stderr} (100%) rename tests/ui/{issues/issue-26217.rs => higher-ranked/forall-implies-static.rs} (100%) rename tests/ui/{issues/issue-26217.stderr => higher-ranked/forall-implies-static.stderr} (100%) rename tests/ui/{issues/issue-25810.rs => higher-ranked/trait-bounds/infer-assoc-type-projection-type.rs} (100%) rename tests/ui/{issues/issue-25343.rs => label/label-in-closure-no-self-shadow.rs} (100%) rename tests/ui/{issues/issue-26237.rs => macros/non-function-call-in-macro.rs} (100%) rename tests/ui/{issues/issue-26237.stderr => macros/non-function-call-in-macro.stderr} (100%) rename tests/ui/{issues/issue-2590.rs => moves/move-field-out-of-shared-self.rs} (100%) rename tests/ui/{issues/issue-2590.stderr => moves/move-field-out-of-shared-self.stderr} (100%) diff --git a/tests/ui/issues/issue-25497.rs b/tests/ui/box/match-box-deref-codegen.rs similarity index 100% rename from tests/ui/issues/issue-25497.rs rename to tests/ui/box/match-box-deref-codegen.rs diff --git a/tests/ui/issues/issue-26468.rs b/tests/ui/codegen/match-enum-range-metadata-misopt.rs similarity index 100% rename from tests/ui/issues/issue-26468.rs rename to tests/ui/codegen/match-enum-range-metadata-misopt.rs diff --git a/tests/ui/issues/issue-25515.rs b/tests/ui/drop/rc-trait-object-double-drop.rs similarity index 100% rename from tests/ui/issues/issue-25515.rs rename to tests/ui/drop/rc-trait-object-double-drop.rs diff --git a/tests/ui/issues/issue-26056.rs b/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.rs similarity index 100% rename from tests/ui/issues/issue-26056.rs rename to tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.rs diff --git a/tests/ui/issues/issue-26056.stderr b/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.stderr similarity index 100% rename from tests/ui/issues/issue-26056.stderr rename to tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.stderr diff --git a/tests/ui/issues/issue-26217.rs b/tests/ui/higher-ranked/forall-implies-static.rs similarity index 100% rename from tests/ui/issues/issue-26217.rs rename to tests/ui/higher-ranked/forall-implies-static.rs diff --git a/tests/ui/issues/issue-26217.stderr b/tests/ui/higher-ranked/forall-implies-static.stderr similarity index 100% rename from tests/ui/issues/issue-26217.stderr rename to tests/ui/higher-ranked/forall-implies-static.stderr diff --git a/tests/ui/issues/issue-25810.rs b/tests/ui/higher-ranked/trait-bounds/infer-assoc-type-projection-type.rs similarity index 100% rename from tests/ui/issues/issue-25810.rs rename to tests/ui/higher-ranked/trait-bounds/infer-assoc-type-projection-type.rs diff --git a/tests/ui/issues/issue-25343.rs b/tests/ui/label/label-in-closure-no-self-shadow.rs similarity index 100% rename from tests/ui/issues/issue-25343.rs rename to tests/ui/label/label-in-closure-no-self-shadow.rs diff --git a/tests/ui/issues/issue-26237.rs b/tests/ui/macros/non-function-call-in-macro.rs similarity index 100% rename from tests/ui/issues/issue-26237.rs rename to tests/ui/macros/non-function-call-in-macro.rs diff --git a/tests/ui/issues/issue-26237.stderr b/tests/ui/macros/non-function-call-in-macro.stderr similarity index 100% rename from tests/ui/issues/issue-26237.stderr rename to tests/ui/macros/non-function-call-in-macro.stderr diff --git a/tests/ui/issues/issue-2590.rs b/tests/ui/moves/move-field-out-of-shared-self.rs similarity index 100% rename from tests/ui/issues/issue-2590.rs rename to tests/ui/moves/move-field-out-of-shared-self.rs diff --git a/tests/ui/issues/issue-2590.stderr b/tests/ui/moves/move-field-out-of-shared-self.stderr similarity index 100% rename from tests/ui/issues/issue-2590.stderr rename to tests/ui/moves/move-field-out-of-shared-self.stderr From c862ccda0bc4c7c80be622bc82f7d1024d90a22b Mon Sep 17 00:00:00 2001 From: zedddie Date: Mon, 22 Jun 2026 23:58:17 +0200 Subject: [PATCH 102/116] bless batch --- tests/ui/box/match-box-deref-codegen.rs | 4 ++++ tests/ui/codegen/match-enum-range-metadata-misopt.rs | 3 +++ tests/ui/drop/rc-trait-object-double-drop.rs | 10 ++++++++++ .../supertrait-with-self-in-type-arg.rs | 2 ++ .../supertrait-with-self-in-type-arg.stderr | 4 ++-- tests/ui/higher-ranked/forall-implies-static.rs | 2 ++ tests/ui/higher-ranked/forall-implies-static.stderr | 4 ++-- .../trait-bounds/infer-assoc-type-projection-type.rs | 2 ++ tests/ui/label/label-in-closure-no-self-shadow.rs | 6 ++++-- tests/ui/macros/non-function-call-in-macro.rs | 2 ++ tests/ui/macros/non-function-call-in-macro.stderr | 2 +- tests/ui/moves/move-field-out-of-shared-self.rs | 2 ++ tests/ui/moves/move-field-out-of-shared-self.stderr | 2 +- 13 files changed, 37 insertions(+), 8 deletions(-) diff --git a/tests/ui/box/match-box-deref-codegen.rs b/tests/ui/box/match-box-deref-codegen.rs index 58dcf416dbebb..30f07c0fd8990 100644 --- a/tests/ui/box/match-box-deref-codegen.rs +++ b/tests/ui/box/match-box-deref-codegen.rs @@ -1,4 +1,8 @@ +//! Regression test for . +//! Test box deref in match arm doesn't generate invalid LLVM IR. +//! Related . //@ run-pass + #[derive(Clone, Debug, PartialEq)] enum Expression { Dummy, diff --git a/tests/ui/codegen/match-enum-range-metadata-misopt.rs b/tests/ui/codegen/match-enum-range-metadata-misopt.rs index 2103b354977f8..a087ef8850b2c 100644 --- a/tests/ui/codegen/match-enum-range-metadata-misopt.rs +++ b/tests/ui/codegen/match-enum-range-metadata-misopt.rs @@ -1,4 +1,7 @@ +//! Regression test for . +//! Range bug in LLVM misoptimized second `if let` inside `for _ in 0..1` away. //@ run-pass + #![allow(dead_code)] enum FooMode { diff --git a/tests/ui/drop/rc-trait-object-double-drop.rs b/tests/ui/drop/rc-trait-object-double-drop.rs index 5eaea683e2128..cbed5b659c583 100644 --- a/tests/ui/drop/rc-trait-object-double-drop.rs +++ b/tests/ui/drop/rc-trait-object-double-drop.rs @@ -1,4 +1,14 @@ +//! Regression test for . +//! Test we don't drop twice when we take a reference through other +//! object like `Rc`. +//! +//! This used to drop Foo twice while coerced to a trait object. +//! `&T`, `Rc` and `&mut` dropped any unsized item each time +//! reference was taken. +//! +//! Value was being dropped when taking the address of an unsized field. //@ run-pass + use std::rc::Rc; struct Foo<'r>(&'r mut i32); diff --git a/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.rs b/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.rs index 99d43ec792b3c..c4969b7f331bd 100644 --- a/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.rs +++ b/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.rs @@ -1,3 +1,5 @@ +//! Regression test for . + trait MapLookup { type MapValue; } diff --git a/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.stderr b/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.stderr index c2168af94969b..1eff8855f760f 100644 --- a/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.stderr +++ b/tests/ui/dyn-compatibility/supertrait-with-self-in-type-arg.stderr @@ -1,12 +1,12 @@ error[E0038]: the trait `Map` is not dyn compatible - --> $DIR/issue-26056.rs:20:17 + --> $DIR/supertrait-with-self-in-type-arg.rs:22:17 | LL | as &dyn Map; | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/issue-26056.rs:9:12 + --> $DIR/supertrait-with-self-in-type-arg.rs:11:12 | LL | trait Map: MapLookup<::Key> { | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter diff --git a/tests/ui/higher-ranked/forall-implies-static.rs b/tests/ui/higher-ranked/forall-implies-static.rs index 422625e73c161..ef3e7a8303f4a 100644 --- a/tests/ui/higher-ranked/forall-implies-static.rs +++ b/tests/ui/higher-ranked/forall-implies-static.rs @@ -1,3 +1,5 @@ +//! Regression test for . + fn foo() where for<'a> T: 'a {} fn bar<'a>() { diff --git a/tests/ui/higher-ranked/forall-implies-static.stderr b/tests/ui/higher-ranked/forall-implies-static.stderr index a875056781955..c74b6a12e7800 100644 --- a/tests/ui/higher-ranked/forall-implies-static.stderr +++ b/tests/ui/higher-ranked/forall-implies-static.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-26217.rs:4:5 + --> $DIR/forall-implies-static.rs:6:5 | LL | fn bar<'a>() { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | foo::<&'a i32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | note: due to a current limitation of the type system, this implies a `'static` lifetime - --> $DIR/issue-26217.rs:1:19 + --> $DIR/forall-implies-static.rs:3:19 | LL | fn foo() where for<'a> T: 'a {} | ^^^^^^^^^^^^^ diff --git a/tests/ui/higher-ranked/trait-bounds/infer-assoc-type-projection-type.rs b/tests/ui/higher-ranked/trait-bounds/infer-assoc-type-projection-type.rs index aa60e8afbef57..0e788a2a746bb 100644 --- a/tests/ui/higher-ranked/trait-bounds/infer-assoc-type-projection-type.rs +++ b/tests/ui/higher-ranked/trait-bounds/infer-assoc-type-projection-type.rs @@ -1,4 +1,6 @@ +//! Regression test for . //@ run-pass + fn main() { let x = X(15); let y = x.foo(); diff --git a/tests/ui/label/label-in-closure-no-self-shadow.rs b/tests/ui/label/label-in-closure-no-self-shadow.rs index 878f248867766..ba573a598a945 100644 --- a/tests/ui/label/label-in-closure-no-self-shadow.rs +++ b/tests/ui/label/label-in-closure-no-self-shadow.rs @@ -1,4 +1,8 @@ +//! Regression test for . +//! Ensure we're not wrongly producing shadowing label warning. +//! More cases added from issue . //@ run-pass + #[allow(unused)] fn main() { || { @@ -6,8 +10,6 @@ fn main() { } }; - // More cases added from issue 31754 - 'label2: loop { break; } diff --git a/tests/ui/macros/non-function-call-in-macro.rs b/tests/ui/macros/non-function-call-in-macro.rs index 71e96677d4bbc..b23fd74c4fd16 100644 --- a/tests/ui/macros/non-function-call-in-macro.rs +++ b/tests/ui/macros/non-function-call-in-macro.rs @@ -1,3 +1,5 @@ +//! Regression test for . + macro_rules! macro_panic { ($not_a_function:expr, $some_argument:ident) => { $not_a_function($some_argument) diff --git a/tests/ui/macros/non-function-call-in-macro.stderr b/tests/ui/macros/non-function-call-in-macro.stderr index d15e5753a25e7..6e38c5e8e3493 100644 --- a/tests/ui/macros/non-function-call-in-macro.stderr +++ b/tests/ui/macros/non-function-call-in-macro.stderr @@ -1,5 +1,5 @@ error[E0618]: expected function, found `{integer}` - --> $DIR/issue-26237.rs:10:18 + --> $DIR/non-function-call-in-macro.rs:12:18 | LL | $not_a_function($some_argument) | ------------------------------- call expression requires function diff --git a/tests/ui/moves/move-field-out-of-shared-self.rs b/tests/ui/moves/move-field-out-of-shared-self.rs index a9a0e5ca4ec16..05c19a8a7a8fb 100644 --- a/tests/ui/moves/move-field-out-of-shared-self.rs +++ b/tests/ui/moves/move-field-out-of-shared-self.rs @@ -1,3 +1,5 @@ +//! Regression test for . + struct Parser { tokens: Vec , } diff --git a/tests/ui/moves/move-field-out-of-shared-self.stderr b/tests/ui/moves/move-field-out-of-shared-self.stderr index 822856652e9df..3720b2bd963f2 100644 --- a/tests/ui/moves/move-field-out-of-shared-self.stderr +++ b/tests/ui/moves/move-field-out-of-shared-self.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `self.tokens` which is behind a shared reference - --> $DIR/issue-2590.rs:11:9 + --> $DIR/move-field-out-of-shared-self.rs:13:9 | LL | self.tokens | ^^^^^^^^^^^ move occurs because `self.tokens` has type `Vec`, which does not implement the `Copy` trait From 2172c51b05018bac56cfb75af4f009d58aab53f1 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Tue, 23 Jun 2026 00:37:42 +0100 Subject: [PATCH 103/116] triagebot: Stop pinging myself https://www.github.com/rust-lang/team/pull/2523 --- triagebot.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index d68e4a4882159..9fd7bad75160f 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1155,7 +1155,6 @@ otherwise, make sure you bump the `FORMAT_VERSION` constant. """ cc = [ "@CraftSpider", - "@aDotInTheVoid", "@Enselic", "@obi1kenobi", ] @@ -1313,7 +1312,7 @@ Please ensure that if you've changed the output: - It's intentional. - The `FORMAT_VERSION` in `src/librustdoc-json-types` is bumped if necessary. """ -cc = ["@aDotInTheVoid", "@obi1kenobi"] +cc = ["@obi1kenobi"] [mentions."tests/ui/derives/deriving-all-codegen.stdout"] message = "Changes to the code generated for builtin derived traits." @@ -1698,7 +1697,7 @@ dep-bumps = [ "/tests/rustdoc-gui" = ["rustdoc"] "/tests/rustdoc-js-std" = ["rustdoc"] "/tests/rustdoc-js/" = ["rustdoc"] -"/tests/rustdoc-json" = ["@aDotInTheVoid"] +"/tests/rustdoc-json" = ["rustdoc"] "/tests/rustdoc-ui" = ["rustdoc"] "/tests/ui" = ["compiler"] "/tests/ui-fulldeps" = ["compiler"] From 1bdb472b1faf52f5728095121e5e7ba2b607168e Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Tue, 23 Jun 2026 01:15:32 +0000 Subject: [PATCH 104/116] Add test. --- tests/ui/uninhabited/void-branch.rs | 10 +++++++ tests/ui/uninhabited/void-branch.stderr | 36 ++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/tests/ui/uninhabited/void-branch.rs b/tests/ui/uninhabited/void-branch.rs index b9e1d70382910..f39cdbae56594 100644 --- a/tests/ui/uninhabited/void-branch.rs +++ b/tests/ui/uninhabited/void-branch.rs @@ -29,4 +29,14 @@ fn with_infallible() { println!() } +fn infallible_with_arg(x: T) -> (T, std::convert::Infallible) { + (x, loop {}) + //~^ ERROR unreachable expression +} + +fn in_if_else(x: String) -> Result { + if x.len() > 0 { Err(infallible_with_arg(x)) } else { Ok(x) } + //~^ ERROR unreachable expression +} + fn main() {} diff --git a/tests/ui/uninhabited/void-branch.stderr b/tests/ui/uninhabited/void-branch.stderr index 15693fc85f4b6..ad30057030870 100644 --- a/tests/ui/uninhabited/void-branch.stderr +++ b/tests/ui/uninhabited/void-branch.stderr @@ -1,3 +1,18 @@ +error: unreachable expression + --> $DIR/void-branch.rs:33:5 + | +LL | (x, loop {}) + | ^^^^-------^ + | | | + | | any code following this expression is unreachable + | unreachable expression + | +note: the lint level is defined here + --> $DIR/void-branch.rs:1:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + error: unreachable expression --> $DIR/void-branch.rs:10:13 | @@ -11,11 +26,6 @@ note: this expression has type `Void`, which is uninhabited | LL | std::mem::uninitialized::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: the lint level is defined here - --> $DIR/void-branch.rs:1:9 - | -LL | #![deny(unreachable_code)] - | ^^^^^^^^^^^^^^^^ error: unreachable expression --> $DIR/void-branch.rs:25:9 @@ -31,5 +41,19 @@ note: this expression has type `Infallible`, which is uninhabited LL | infallible(); | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: unreachable expression + --> $DIR/void-branch.rs:38:48 + | +LL | if x.len() > 0 { Err(infallible_with_arg(x)) } else { Ok(x) } + | ----------------------^ unreachable expression + | | + | any code following this expression is unreachable + | +note: this expression has type `(String, Infallible)`, which is uninhabited + --> $DIR/void-branch.rs:38:26 + | +LL | if x.len() > 0 { Err(infallible_with_arg(x)) } else { Ok(x) } + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors From 490d32c3beec697465459d2683b6ff12ecddc170 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Mon, 22 Jun 2026 01:19:17 +0000 Subject: [PATCH 105/116] Follow goto and drop when linting unreachable code. This removes a few false-positives due to extraneous drops. --- .../src/lint_and_remove_uninhabited.rs | 23 ++++++++++++++----- library/std/src/sync/poison.rs | 3 --- tests/ui/uninhabited/void-branch.rs | 1 - tests/ui/uninhabited/void-branch.stderr | 16 +------------ 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs b/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs index 81e98585995fd..b359077753fd6 100644 --- a/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs +++ b/compiler/rustc_mir_transform/src/lint_and_remove_uninhabited.rs @@ -93,8 +93,8 @@ fn find_unreachable_code_from<'tcx>( bb: BasicBlock, body: &Body<'tcx>, ) -> Option<(SourceInfo, &'static str)> { - let bb = &body.basic_blocks[bb]; - for stmt in &bb.statements { + let bbdata = &body.basic_blocks[bb]; + for stmt in &bbdata.statements { match &stmt.kind { // Ignore the implicit `()` return place assignment for unit functions/blocks StatementKind::Assign((_, Rvalue::Use(Operand::Constant(const_), _))) @@ -108,7 +108,10 @@ fn find_unreachable_code_from<'tcx>( StatementKind::Assign((place, _)) if place.as_local() == Some(RETURN_PLACE) => { continue; } - StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => { + // Ignore statements inserted by MIR building that do not correspond to user code. + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::BackwardIncompatibleDropHint { .. } => { continue; } StatementKind::FakeRead(..) => return Some((stmt.source_info, "definition")), @@ -116,10 +119,18 @@ fn find_unreachable_code_from<'tcx>( } } - let term = bb.terminator(); + let term = bbdata.terminator(); match term.kind { - // No user code in this bb, and our goto target may be reachable via other paths - TerminatorKind::Goto { .. } | TerminatorKind::Return => None, + // The user does not care for `goto` and compiler-generated drops. If the target block is + // only reachable through those terminators, continue searching there. + TerminatorKind::Goto { target } | TerminatorKind::Drop { target, .. } => { + if &body.basic_blocks.predecessors()[target][..] == &[bb] { + find_unreachable_code_from(target, body) + } else { + None + } + } + TerminatorKind::Return => None, _ => Some((term.source_info, "expression")), } } diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 9f40c01546632..ee7e5f8586700 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -57,9 +57,6 @@ //! //! [`Once`]: crate::sync::Once -// If we are not unwinding, `PoisonError` is uninhabited. -#![cfg_attr(not(panic = "unwind"), expect(unreachable_code))] - #[stable(feature = "rust1", since = "1.0.0")] pub use self::condvar::Condvar; #[unstable(feature = "mapped_lock_guards", issue = "117108")] diff --git a/tests/ui/uninhabited/void-branch.rs b/tests/ui/uninhabited/void-branch.rs index f39cdbae56594..0f3e6987fead5 100644 --- a/tests/ui/uninhabited/void-branch.rs +++ b/tests/ui/uninhabited/void-branch.rs @@ -36,7 +36,6 @@ fn infallible_with_arg(x: T) -> (T, std::convert::Infallible) { fn in_if_else(x: String) -> Result { if x.len() > 0 { Err(infallible_with_arg(x)) } else { Ok(x) } - //~^ ERROR unreachable expression } fn main() {} diff --git a/tests/ui/uninhabited/void-branch.stderr b/tests/ui/uninhabited/void-branch.stderr index ad30057030870..7d886056098aa 100644 --- a/tests/ui/uninhabited/void-branch.stderr +++ b/tests/ui/uninhabited/void-branch.stderr @@ -41,19 +41,5 @@ note: this expression has type `Infallible`, which is uninhabited LL | infallible(); | ^^^^^^^^^^^^ -error: unreachable expression - --> $DIR/void-branch.rs:38:48 - | -LL | if x.len() > 0 { Err(infallible_with_arg(x)) } else { Ok(x) } - | ----------------------^ unreachable expression - | | - | any code following this expression is unreachable - | -note: this expression has type `(String, Infallible)`, which is uninhabited - --> $DIR/void-branch.rs:38:26 - | -LL | if x.len() > 0 { Err(infallible_with_arg(x)) } else { Ok(x) } - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 24d44396b5be47a535bf5349d4df02e7c87b5305 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 22 Jun 2026 13:47:30 +0000 Subject: [PATCH 106/116] Use `cfg_select` in `std::os` This reverts commit 7bc501687b39a9d47938c58f2661b54f014ff7d3. --- library/std/src/os/mod.rs | 183 ++++++++++++++------------------------ 1 file changed, 66 insertions(+), 117 deletions(-) diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 76374402be4b3..44ddb55c920f4 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -6,121 +6,83 @@ pub mod raw; -// The code below could be written clearer using `cfg_if!`. However, the items below are -// publicly exported by `std` and external tools can have trouble analysing them because of the use -// of a macro that is not vendored by Rust and included in the toolchain. -// See https://github.com/rust-analyzer/rust-analyzer/issues/6038. +// # Important platforms -// On certain platforms right now the "main modules" modules that are -// documented don't compile (missing things in `libc` which is empty), -// so just omit them with an empty module and add the "unstable" attribute. - -// darwin, unix, linux, wasi and windows are handled a bit differently. -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod darwin {} -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod unix {} -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod linux {} -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod wasi {} -#[cfg(all( - doc, +// We always want to show documentation for the most important platforms, +// so these are handled specially here. +// +// FIXME: On certain platforms compilation errors (due to empty `libc`), +// prevent this, so we substitute an unstable empty module. +#[cfg(doc)] +cfg_select! { any( all(target_arch = "wasm32", not(target_os = "wasi")), all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod windows {} + ) => { + #[unstable(issue = "none", feature = "std_internals")] + pub mod darwin {} -// darwin -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(target_vendor = "apple", doc))] -pub mod darwin; + #[unstable(issue = "none", feature = "std_internals")] + pub mod unix {} -// unix -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(all(not(target_os = "hermit"), any(unix, doc)))] -pub mod unix; + #[unstable(issue = "none", feature = "std_internals")] + pub mod linux {} -// linux -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(target_os = "linux", doc))] -pub mod linux; + #[unstable(issue = "none", feature = "std_internals")] + pub mod wasi {} -// wasi -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(target_os = "wasi", any(target_env = "p1", target_env = "p2"), doc))] -pub mod wasi; + #[unstable(issue = "none", feature = "std_internals")] + pub mod windows {} + } + _ => { + // important platforms + pub mod darwin; + pub mod linux; + pub mod unix; + pub mod wasi; + pub mod wasip2; + pub mod windows; + } +} +#[cfg(not(doc))] // to prevent double module declarations +cfg_select! { + target_family = "unix" => { + pub mod unix; + #[cfg(target_vendor = "apple")] + pub mod darwin; + #[cfg(target_os = "linux")] + pub mod linux; + } + target_family = "wasm" => { + #[cfg(any(target_env = "p1", target_env = "p2"))] + pub mod wasi; + #[cfg(target_env = "p2")] + pub mod wasip2; + } + target_family = "windows" => { + pub mod windows; + } + _ => { /* handled below */ } +} -#[cfg(any(all(target_os = "wasi", target_env = "p2"), doc))] -pub mod wasip2; +// # Special modules -// windows -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(windows, doc))] -pub mod windows; +#[cfg(any( + unix, + target_os = "hermit", + target_os = "trusty", + target_os = "wasi", + target_os = "motor", + doc +))] +pub mod fd; + +#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))] +mod net; + +// # Ordinary platforms +// `cfg(doc)` not handled specially -// Others. #[cfg(target_os = "aix")] pub mod aix; #[cfg(target_os = "android")] @@ -183,16 +145,3 @@ pub mod vita; pub mod vxworks; #[cfg(target_os = "xous")] pub mod xous; - -#[cfg(any( - unix, - target_os = "hermit", - target_os = "trusty", - target_os = "wasi", - target_os = "motor", - doc -))] -pub mod fd; - -#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))] -mod net; From 5d07ed58ead1b457aa52e6c5c62753764198d069 Mon Sep 17 00:00:00 2001 From: Arhan Chaudhary Date: Tue, 23 Jun 2026 05:09:58 +0000 Subject: [PATCH 107/116] slice_split_once: bounds check optimization note --- library/core/src/slice/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 9b077f1f9c1bd..7ab476e785d16 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2530,6 +2530,7 @@ impl [T] { F: FnMut(&T) -> bool, { let index = self.iter().position(pred)?; + // Slice bounds checks optimized are away (as of June 2026) Some((&self[..index], &self[index + 1..])) } @@ -2558,6 +2559,7 @@ impl [T] { F: FnMut(&T) -> bool, { let index = self.iter().rposition(pred)?; + // Slice bounds checks optimized are away (as of June 2026) Some((&self[..index], &self[index + 1..])) } From e638ebef2b89e25a872504d5632d91eb6af37d8a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 15 Jun 2026 19:50:56 +0200 Subject: [PATCH 108/116] Lift the same-signature restriction for `extern "tail"` --- compiler/rustc_codegen_ssa/src/mir/block.rs | 5 +- compiler/rustc_hir_typeck/src/check.rs | 2 +- .../rustc_mir_build/src/check_tail_calls.rs | 21 +++++++- compiler/rustc_target/src/callconv/mod.rs | 3 ++ compiler/rustc_ty_utils/src/abi.rs | 6 ++- .../no-unsized-arguments.aarch64.stderr | 31 ++++++++++++ .../no-unsized-arguments.rs | 50 +++++++++++++++++++ .../no-unsized-arguments.x86.stderr | 31 ++++++++++++ .../no-unsized-arguments.x86_64.stderr | 31 ++++++++++++ .../explicit-tail-calls/signature-mismatch.rs | 12 +++-- .../signature-mismatch.stderr | 17 +++++-- .../tailcc-no-signature-restriction.rs | 49 ++++++++++++++++++ 12 files changed, 245 insertions(+), 13 deletions(-) create mode 100644 tests/ui/explicit-tail-calls/no-unsized-arguments.aarch64.stderr create mode 100644 tests/ui/explicit-tail-calls/no-unsized-arguments.rs create mode 100644 tests/ui/explicit-tail-calls/no-unsized-arguments.x86.stderr create mode 100644 tests/ui/explicit-tail-calls/no-unsized-arguments.x86_64.stderr create mode 100644 tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d4932adeda1f9..ab983ceb72ffc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1317,7 +1317,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } LocalRef::Operand(arg) => { let Ref(place_value) = arg.val else { - bug!("only `Ref` should use `PassMode::Indirect`"); + bug!( + "only `Ref` should use `PassMode::Indirect`, but got {:?}", + arg.val + ); }; bx.typed_place_copy(place_value, tmp.val, fn_abi.args[i].layout); op.val = arg.val; diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 5fe1f4191c93f..1780430567a80 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -90,7 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>( } // Check that argument is Sized. - if !params_can_be_unsized { + if !params_can_be_unsized || fn_sig.abi() == rustc_abi::ExternAbi::RustTail { fcx.require_type_is_sized( param_ty, param.ty_span, diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 8052ee26df841..ac9f6e384cf04 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -147,7 +147,9 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { // ``` // we should think what is the expected behavior here. // (we should probably just accept this by revealing opaques?) - if caller_sig.inputs_and_output != callee_sig.inputs_and_output { + if caller_sig.inputs_and_output != callee_sig.inputs_and_output + && !matches!(callee_sig.abi(), ExternAbi::RustTail) + { let caller_ty = self.tcx.type_of(self.caller_def_id).skip_binder(); self.report_signature_mismatch( @@ -189,6 +191,12 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { if callee_sig.c_variadic() { self.report_c_variadic_callee(expr.span); } + + for &arg_ty in callee_sig.inputs() { + if !arg_ty.is_sized(self.tcx, self.typing_env) { + self.report_unsized_argument(expr.span, arg_ty); + } + } } /// Returns true if the caller function needs a location argument @@ -417,6 +425,17 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { self.found_errors = Err(err); } + + fn report_unsized_argument(&mut self, sp: Span, arg_ty: Ty<'tcx>) { + let err = self + .tcx + .dcx() + .struct_span_err(sp, format!("unsized arguments cannot be used in a tail call")) + .with_note(format!("unsized argument of type `{arg_ty}`")) + .emit(); + + self.found_errors = Err(err); + } } impl<'a, 'tcx> Visitor<'a, 'tcx> for TailCallCkVisitor<'a, 'tcx> { diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 7e1eafa10097f..30d16b5c7b1c9 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -827,6 +827,9 @@ impl<'a, Ty> FnAbi<'a, Ty> { ArgAttribute::default() }; arg.cast_to_with_attrs(Reg { kind: RegKind::Integer, size }, attr.into()); + } else if self.conv == CanonAbi::RustTail { + assert!(arg.layout.is_sized(), "extern \"tail\" arguments must be sized"); + arg.pass_by_stack_offset(None); } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index e782557d126bf..5c67021c59c59 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -458,8 +458,10 @@ fn fn_abi_sanity_check<'tcx>( // omitted entirely in the calling convention. assert!(arg.is_ignore()); } - if let PassMode::Indirect { on_stack, .. } = arg.mode { - assert!(!on_stack, "rust abi shouldn't use on_stack"); + if let PassMode::Indirect { on_stack, .. } = arg.mode + && spec_abi != ExternAbi::RustTail + { + assert!(!on_stack, "rustic abi {spec_abi:?} shouldn't use on_stack"); } } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { assert_matches!( diff --git a/tests/ui/explicit-tail-calls/no-unsized-arguments.aarch64.stderr b/tests/ui/explicit-tail-calls/no-unsized-arguments.aarch64.stderr new file mode 100644 index 0000000000000..33e190e1a4a7f --- /dev/null +++ b/tests/ui/explicit-tail-calls/no-unsized-arguments.aarch64.stderr @@ -0,0 +1,31 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/no-unsized-arguments.rs:40:42 + | +LL | extern "tail" fn unsized_argument(x: [u8]) -> u8 { + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +help: function arguments must have a statically known size, borrowed slices always have a known size + | +LL | extern "tail" fn unsized_argument(x: &[u8]) -> u8 { + | + + +error: unsized arguments cannot be used in a tail call + --> $DIR/no-unsized-arguments.rs:33:5 + | +LL | become unsized_argument(b); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsized argument of type `[u8]` + +error: unsized arguments cannot be used in a tail call + --> $DIR/no-unsized-arguments.rs:48:5 + | +LL | become unsized_argument(*b); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsized argument of type `[u8]` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/explicit-tail-calls/no-unsized-arguments.rs b/tests/ui/explicit-tail-calls/no-unsized-arguments.rs new file mode 100644 index 0000000000000..a0c5b53d8df0c --- /dev/null +++ b/tests/ui/explicit-tail-calls/no-unsized-arguments.rs @@ -0,0 +1,50 @@ +//@ add-minicore +//@ ignore-backends: gcc +//@ min-llvm-version: 22 +// +//@ revisions: x86 x86_64 aarch64 +// +//@ [x86] compile-flags: --target=i686-unknown-linux-gnu +//@ [x86] needs-llvm-components: x86 +//@ [x86_64] compile-flags: --target=x86_64-unknown-linux-gnu +//@ [x86_64] needs-llvm-components: x86 +//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu +//@ [aarch64] needs-llvm-components: aarch64 +#![feature(explicit_tail_calls, rust_tail_cc, unsized_fn_params, no_core)] +#![allow(incomplete_features, internal_features)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +extern "C" { + fn extract(_: [u8]) -> u8; +} + +fn vanilla(b: [u8]) -> u8 { + fn unsized_argument(x: [u8]) -> u8 { + unsafe { extract(x) } + } + + // Non-tail call. + let _ = unsized_argument(b); + + become unsized_argument(b); + //~^ ERROR unsized arguments cannot be used in a tail call +} + +extern "tail" fn tailcc(b: &[u8]) -> u8 { + // `extern "tail"` is special because we also can't unsized parameters in standard definitions + // and calls. + extern "tail" fn unsized_argument(x: [u8]) -> u8 { + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + unsafe { extract(x) } + } + + // Vanilla call. + let _ = unsized_argument(*b); + + become unsized_argument(*b); + //~^ ERROR unsized arguments cannot be used in a tail call +} diff --git a/tests/ui/explicit-tail-calls/no-unsized-arguments.x86.stderr b/tests/ui/explicit-tail-calls/no-unsized-arguments.x86.stderr new file mode 100644 index 0000000000000..33e190e1a4a7f --- /dev/null +++ b/tests/ui/explicit-tail-calls/no-unsized-arguments.x86.stderr @@ -0,0 +1,31 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/no-unsized-arguments.rs:40:42 + | +LL | extern "tail" fn unsized_argument(x: [u8]) -> u8 { + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +help: function arguments must have a statically known size, borrowed slices always have a known size + | +LL | extern "tail" fn unsized_argument(x: &[u8]) -> u8 { + | + + +error: unsized arguments cannot be used in a tail call + --> $DIR/no-unsized-arguments.rs:33:5 + | +LL | become unsized_argument(b); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsized argument of type `[u8]` + +error: unsized arguments cannot be used in a tail call + --> $DIR/no-unsized-arguments.rs:48:5 + | +LL | become unsized_argument(*b); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsized argument of type `[u8]` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/explicit-tail-calls/no-unsized-arguments.x86_64.stderr b/tests/ui/explicit-tail-calls/no-unsized-arguments.x86_64.stderr new file mode 100644 index 0000000000000..33e190e1a4a7f --- /dev/null +++ b/tests/ui/explicit-tail-calls/no-unsized-arguments.x86_64.stderr @@ -0,0 +1,31 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/no-unsized-arguments.rs:40:42 + | +LL | extern "tail" fn unsized_argument(x: [u8]) -> u8 { + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +help: function arguments must have a statically known size, borrowed slices always have a known size + | +LL | extern "tail" fn unsized_argument(x: &[u8]) -> u8 { + | + + +error: unsized arguments cannot be used in a tail call + --> $DIR/no-unsized-arguments.rs:33:5 + | +LL | become unsized_argument(b); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsized argument of type `[u8]` + +error: unsized arguments cannot be used in a tail call + --> $DIR/no-unsized-arguments.rs:48:5 + | +LL | become unsized_argument(*b); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: unsized argument of type `[u8]` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/explicit-tail-calls/signature-mismatch.rs b/tests/ui/explicit-tail-calls/signature-mismatch.rs index a32ac9d8bfee3..bed480f60f63b 100644 --- a/tests/ui/explicit-tail-calls/signature-mismatch.rs +++ b/tests/ui/explicit-tail-calls/signature-mismatch.rs @@ -1,5 +1,5 @@ #![expect(incomplete_features)] -#![feature(explicit_tail_calls)] +#![feature(explicit_tail_calls, rust_tail_cc)] #![feature(c_variadic)] fn _f0((): ()) { @@ -8,26 +8,30 @@ fn _f0((): ()) { fn _g0() {} - fn _f1() { become _g1(()); //~ error: mismatched signatures } fn _g1((): ()) {} - extern "C" fn _f2() { become _g2(); //~ error: mismatched function ABIs } fn _g2() {} - fn _f3() { become _g3(); //~ error: mismatched function ABIs } extern "C" fn _g3() {} +extern "tail" fn _tailcc() {} + +fn _f4() { + // tailcc does not need the signatures to match, + // but only tailcc can tail call tailcc. + become _tailcc(); //~ error: mismatched function ABIs +} fn main() {} diff --git a/tests/ui/explicit-tail-calls/signature-mismatch.stderr b/tests/ui/explicit-tail-calls/signature-mismatch.stderr index ba9e9dcb98483..6e26f1c075539 100644 --- a/tests/ui/explicit-tail-calls/signature-mismatch.stderr +++ b/tests/ui/explicit-tail-calls/signature-mismatch.stderr @@ -9,7 +9,7 @@ LL | become _g0(); = note: callee signature: `fn()` error: mismatched signatures - --> $DIR/signature-mismatch.rs:13:5 + --> $DIR/signature-mismatch.rs:12:5 | LL | become _g1(()); | ^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | become _g1(()); = note: callee signature: `fn(())` error: mismatched function ABIs - --> $DIR/signature-mismatch.rs:20:5 + --> $DIR/signature-mismatch.rs:18:5 | LL | become _g2(); | ^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | become _g2(); = note: caller ABI is `"C"`, while callee ABI is `"Rust"` error: mismatched function ABIs - --> $DIR/signature-mismatch.rs:27:5 + --> $DIR/signature-mismatch.rs:24:5 | LL | become _g3(); | ^^^^^^^^^^^^ @@ -36,5 +36,14 @@ LL | become _g3(); = note: `become` requires caller and callee to have the same ABI = note: caller ABI is `"Rust"`, while callee ABI is `"C"` -error: aborting due to 4 previous errors +error: mismatched function ABIs + --> $DIR/signature-mismatch.rs:34:5 + | +LL | become _tailcc(); + | ^^^^^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have the same ABI + = note: caller ABI is `"Rust"`, while callee ABI is `"tail"` + +error: aborting due to 5 previous errors diff --git a/tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs b/tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs new file mode 100644 index 0000000000000..9c9085ca1daca --- /dev/null +++ b/tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs @@ -0,0 +1,49 @@ +//@ run-pass +//@ ignore-backends: gcc +//@ min-llvm-version: 22 +//@ revisions: x86_64 aarch64 +// +// FIXME: enable x86 on LLVM 23. +//@ [x86_64] only-x86_64 +//@ [aarch64] only-aarch64 +#![feature(explicit_tail_calls, rust_tail_cc)] + +#[inline(never)] +pub extern "tail" fn add() -> u64 { + #[inline(never)] + extern "tail" fn add(a: u64, b: u64) -> u64 { + a.wrapping_add(b) + } + + become add(1, 2); +} + +#[inline(never)] +pub extern "tail" fn pass_struct(a: u64, d: u64) -> u64 { + #[derive(Clone, Copy)] + pub struct Large { + pub a: u64, + pub b: u64, + pub c: u64, + pub d: u64, + } + + #[inline(never)] + extern "tail" fn add(large: Large) -> u64 { + let _ = large.b; + let _ = large.c; + large.a.wrapping_add(large.d) + } + + let large = Large { a, b: 0xBBBB_BBBB_BBBB_BBBB, c: 0xCCCC_CCCC_CCCC_CCCC, d }; + become add(large); +} + +fn main() { + assert_eq!(add(), 3); + + // FIXME: LLVM 22 has a bug which makes this miscompile. + if false { + assert_eq!(pass_struct(5, 6), 5 + 6); + } +} From 24a66cb151819237b6580ff3d7588a896983eda4 Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Mon, 22 Jun 2026 17:06:32 +0200 Subject: [PATCH 109/116] Improve unknown crate_type diagnostic suggestions --- .../src/attributes/crate_level.rs | 6 +- tests/ui/attributes/invalid-crate-type.rs | 49 ++++++++++++ tests/ui/attributes/invalid-crate-type.stderr | 74 ++++++++++++++++--- 3 files changed, 116 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index eb78bc0775f6b..ac5251838300a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -2,7 +2,7 @@ use rustc_feature::AttributeStability; use rustc_hir::attrs::{CrateType, WindowsSubsystemKind}; use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES; use rustc_span::Symbol; -use rustc_span::edit_distance::find_best_match_for_name; +use rustc_span::edit_distance::find_best_match_for_name_with_substrings; use super::prelude::*; use crate::diagnostics::{UnknownCrateTypes, UnknownCrateTypesSuggestion}; @@ -49,10 +49,10 @@ impl CombineAttributeParser for CrateTypeParser { let Ok(crate_type) = crate_type.try_into() else { // We don't error on invalid `#![crate_type]` when not applied to a crate if cx.shared.target == Target::Crate { - let candidate = find_best_match_for_name( + let candidate = find_best_match_for_name_with_substrings( &CrateType::all_stable().iter().map(|(name, _)| *name).collect::>(), crate_type, - None, + Some(5), ); let span = n.value_span; cx.emit_lint( diff --git a/tests/ui/attributes/invalid-crate-type.rs b/tests/ui/attributes/invalid-crate-type.rs index c233e7d5e3db8..aea75f4cfad90 100644 --- a/tests/ui/attributes/invalid-crate-type.rs +++ b/tests/ui/attributes/invalid-crate-type.rs @@ -1,5 +1,8 @@ // regression test for issue 11256 #![crate_type="foo"] //~ ERROR invalid `crate_type` value +//~| NOTE `#[deny(unknown_crate_types)]` on by default +//~| HELP did you mean +//~| SUGGESTION lib // Tests for suggestions (#53958) @@ -43,6 +46,52 @@ //~| HELP did you mean //~| SUGGESTION cdylib +// substring matching tests +#![crate_type="binary"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION bin + +#![crate_type="library"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION lib + +#![crate_type="rustlib"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION rlib + +#![crate_type="dynamiclib"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION dylib + +#![crate_type="dylibrary"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION dylib + +#![crate_type="cdynamiclib"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION cdylib + +#![crate_type="cdylibrary"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION cdylib + +#![crate_type="staticlibrary"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION staticlib + +#![crate_type="procedural-macro"] +//~^ ERROR invalid `crate_type` value +//~| HELP did you mean +//~| SUGGESTION proc-macro + fn main() { return } diff --git a/tests/ui/attributes/invalid-crate-type.stderr b/tests/ui/attributes/invalid-crate-type.stderr index 3eae04678b4a7..2c7663b10925e 100644 --- a/tests/ui/attributes/invalid-crate-type.stderr +++ b/tests/ui/attributes/invalid-crate-type.stderr @@ -2,57 +2,111 @@ error: invalid `crate_type` value --> $DIR/invalid-crate-type.rs:2:15 | LL | #![crate_type="foo"] - | ^^^^^ + | ^^^^^ help: did you mean: `"lib"` | = note: `#[deny(unknown_crate_types)]` on by default error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:6:15 + --> $DIR/invalid-crate-type.rs:9:15 | LL | #![crate_type="statoclib"] | ^^^^^^^^^^^ help: did you mean: `"staticlib"` error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:11:15 + --> $DIR/invalid-crate-type.rs:14:15 | LL | #![crate_type="procmacro"] | ^^^^^^^^^^^ help: did you mean: `"proc-macro"` error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:16:15 + --> $DIR/invalid-crate-type.rs:19:15 | LL | #![crate_type="static-lib"] | ^^^^^^^^^^^^ help: did you mean: `"staticlib"` error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:21:15 + --> $DIR/invalid-crate-type.rs:24:15 | LL | #![crate_type="drylib"] | ^^^^^^^^ help: did you mean: `"dylib"` error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:26:15 + --> $DIR/invalid-crate-type.rs:29:15 | LL | #![crate_type="dlib"] | ^^^^^^ help: did you mean: `"lib"` error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:31:15 + --> $DIR/invalid-crate-type.rs:34:15 | LL | #![crate_type="lob"] | ^^^^^ help: did you mean: `"lib"` error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:36:15 + --> $DIR/invalid-crate-type.rs:39:15 | LL | #![crate_type="bon"] | ^^^^^ help: did you mean: `"bin"` error: invalid `crate_type` value - --> $DIR/invalid-crate-type.rs:41:15 + --> $DIR/invalid-crate-type.rs:44:15 | LL | #![crate_type="cdalib"] | ^^^^^^^^ help: did you mean: `"cdylib"` -error: aborting due to 9 previous errors +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:50:15 + | +LL | #![crate_type="binary"] + | ^^^^^^^^ help: did you mean: `"bin"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:55:15 + | +LL | #![crate_type="library"] + | ^^^^^^^^^ help: did you mean: `"lib"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:60:15 + | +LL | #![crate_type="rustlib"] + | ^^^^^^^^^ help: did you mean: `"rlib"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:65:15 + | +LL | #![crate_type="dynamiclib"] + | ^^^^^^^^^^^^ help: did you mean: `"dylib"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:70:15 + | +LL | #![crate_type="dylibrary"] + | ^^^^^^^^^^^ help: did you mean: `"dylib"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:75:15 + | +LL | #![crate_type="cdynamiclib"] + | ^^^^^^^^^^^^^ help: did you mean: `"cdylib"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:80:15 + | +LL | #![crate_type="cdylibrary"] + | ^^^^^^^^^^^^ help: did you mean: `"cdylib"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:85:15 + | +LL | #![crate_type="staticlibrary"] + | ^^^^^^^^^^^^^^^ help: did you mean: `"staticlib"` + +error: invalid `crate_type` value + --> $DIR/invalid-crate-type.rs:90:15 + | +LL | #![crate_type="procedural-macro"] + | ^^^^^^^^^^^^^^^^^^ help: did you mean: `"proc-macro"` + +error: aborting due to 18 previous errors From e290ddc80f7c119f328ba8c53ce23f45ce4c915f Mon Sep 17 00:00:00 2001 From: Roland Xu Date: Tue, 23 Jun 2026 21:38:57 +0800 Subject: [PATCH 110/116] mailmap: update mu001999 --- .mailmap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index d1e5b3f519591..9166494632a00 100644 --- a/.mailmap +++ b/.mailmap @@ -491,7 +491,6 @@ Milan Landaverde mjptree Ms2ger msizanoen1 -mu001999 Mukilan Thiagarajan Nadrieril Feneanar Nadrieril Feneanar @@ -603,6 +602,7 @@ Robert Habermeier Robert Millar Roc Yu Rohit Joshi Rohit Joshi +Roland Xu Ross Smyth <18294397+RossSmyth@users.noreply.github.com> Ross Smyth <18294397+RossSmyth@users.noreply.github.com> Ross Smyth <18294397+RossSmyth@users.noreply.github.com> From bd73fb8e296503d9b7aecfe58350cce0bcc249ad Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 22 Jun 2026 17:49:19 +0200 Subject: [PATCH 111/116] Only load the feature list once in the entire resolver --- .../rustc_resolve/src/build_reduced_graph.rs | 10 ++++---- compiler/rustc_resolve/src/def_collector.rs | 4 ++-- compiler/rustc_resolve/src/error_helper.rs | 18 +++++++++------ compiler/rustc_resolve/src/ident.rs | 14 +++++------ compiler/rustc_resolve/src/imports.rs | 7 +++--- compiler/rustc_resolve/src/late.rs | 23 +++++++++---------- .../rustc_resolve/src/late/diagnostics.rs | 9 ++++---- compiler/rustc_resolve/src/lib.rs | 16 ++++++------- compiler/rustc_resolve/src/macros.rs | 11 ++++----- 9 files changed, 56 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 911c6142e4b22..bb9bf8976f672 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -548,7 +548,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { root_id, vis, vis_span: item.vis.span, - on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, &item.attrs), + on_unknown_attr: OnUnknownData::from_attrs(self.r, &item.attrs), }); self.r.indeterminate_imports.push(import); @@ -863,7 +863,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { || ast::attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); self.parent_scope.module = module.to_module(); - if let Some(directive) = OnUnknownData::from_attrs(self.r.tcx, &item.attrs) { + if let Some(directive) = OnUnknownData::from_attrs(self.r, &item.attrs) { self.r.on_unknown_data.insert(local_def_id, directive); } } @@ -1040,7 +1040,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { module_path: Vec::new(), vis, vis_span: item.vis.span, - on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, &item.attrs), + on_unknown_attr: OnUnknownData::from_attrs(self.r, &item.attrs), }); if used { self.r.import_use_map.insert(import, Used::Other); @@ -1172,7 +1172,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { module_path: Vec::new(), vis: Visibility::Restricted(CRATE_DEF_ID), vis_span: item.vis.span, - on_unknown_attr: OnUnknownData::from_attrs(this.r.tcx, &item.attrs), + on_unknown_attr: OnUnknownData::from_attrs(this.r, &item.attrs), }) }; @@ -1353,7 +1353,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { module_path: Vec::new(), vis, vis_span: item.vis.span, - on_unknown_attr: OnUnknownData::from_attrs(self.r.tcx, &item.attrs), + on_unknown_attr: OnUnknownData::from_attrs(self.r, &item.attrs), }); self.r.import_use_map.insert(import, Used::Other); let import_decl = self.r.new_import_decl(decl, import); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index cdc2df5bf2945..a5049339382f7 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -186,7 +186,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Does that prevents errors from happening? maybe let mut parser = AttributeParser::new( &self.r.tcx.sess, - self.r.tcx.features(), + self.r.features, self.r.tcx().registered_tools(()), ShouldEmit::Nothing, ); @@ -433,7 +433,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so // to avoid affecting stable we have to feature gate the not creating // anon consts - if !self.r.tcx.features().min_generic_const_args() { + if !self.r.features.min_generic_const_args() { let parent = self .create_def(constant.id, None, DefKind::AnonConst, constant.value.span) .def_id(); diff --git a/compiler/rustc_resolve/src/error_helper.rs b/compiler/rustc_resolve/src/error_helper.rs index 81c1b6fa8d675..1b7d799cadd35 100644 --- a/compiler/rustc_resolve/src/error_helper.rs +++ b/compiler/rustc_resolve/src/error_helper.rs @@ -1628,7 +1628,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { in_module.for_each_child(self, |this, ident, orig_ident_span, ns, name_binding| { // Avoid non-importable candidates. if name_binding.is_assoc_item() - && !this.tcx.features().import_trait_associated_functions() + && !this.features.import_trait_associated_functions() { return; } @@ -1809,10 +1809,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) => { if span.allows_unstable(feature) { true - } else if self.tcx.features().enabled(feature) { + } else if self.features.enabled(feature) { true } else if let Some(implied_by) = implied_by - && self.tcx.features().enabled(implied_by) + && self.features.enabled(implied_by) { true } else { @@ -4144,13 +4144,17 @@ pub(crate) struct OnUnknownData { } impl OnUnknownData { - pub(crate) fn from_attrs<'tcx>( - tcx: TyCtxt<'tcx>, + pub(crate) fn from_attrs( + r: &Resolver<'_, '_>, attrs: &[ast::Attribute], ) -> Option { - if tcx.features().diagnostic_on_unknown() + if r.features.diagnostic_on_unknown() && let Some(Attribute::Parsed(AttributeKind::OnUnknown { directive, .. })) = - AttributeParser::parse_limited(tcx.sess, attrs, &[sym::diagnostic, sym::on_unknown]) + AttributeParser::parse_limited( + r.tcx.sess, + attrs, + &[sym::diagnostic, sym::on_unknown], + ) { Some(Self { directive: directive? }) } else { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 2e69405811db4..574e932cc75d8 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -746,7 +746,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::BuiltinTypes => match self.builtin_type_decls.get(&ident.name) { Some(decl) => { if matches!(ident.name, sym::f16) - && !self.tcx.features().f16() + && !self.features.f16() && !orig_ident_span.allows_unstable(sym::f16) && finalize.is_some() { @@ -759,7 +759,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit(); } if matches!(ident.name, sym::f128) - && !self.tcx.features().f128() + && !self.features.f128() && !orig_ident_span.allows_unstable(sym::f128) && finalize.is_some() { @@ -1535,7 +1535,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } RibKind::ConstParamTy => { - if !self.tcx.features().generic_const_parameter_types() { + if !self.features.generic_const_parameter_types() { if let Some(span) = finalize { self.report_error( span, @@ -1564,7 +1564,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } NoConstantGenericsReason::NonTrivialConstArg => { ResolutionError::ParamInNonTrivialAnonConst { - is_gca: self.tcx.features().generic_const_args(), + is_gca: self.features.generic_const_args(), name: rib_ident.name, param_kind: ParamKindInNonTrivialAnonConst::Type, } @@ -1629,7 +1629,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | RibKind::ForwardGenericParamBan(_) => continue, RibKind::ConstParamTy => { - if !self.tcx.features().generic_const_parameter_types() { + if !self.features.generic_const_parameter_types() { if let Some(span) = finalize { self.report_error( span, @@ -1656,7 +1656,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } NoConstantGenericsReason::NonTrivialConstArg => { ResolutionError::ParamInNonTrivialAnonConst { - is_gca: self.tcx.features().generic_const_args(), + is_gca: self.features.generic_const_args(), name: rib_ident.name, param_kind: ParamKindInNonTrivialAnonConst::Const { name: rib_ident.name, @@ -2019,7 +2019,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module, || { let import_inherent_item_error_flag = - self.tcx.features().import_trait_associated_functions() + self.features.import_trait_associated_functions() && matches!( res, Res::Def( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d823da9756c81..a3cb526e60a87 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -779,7 +779,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match import_decls[ns] { PendingDecl::Ready(Some(import_decl)) => { if import_decl.is_assoc_item() - && !this.tcx.features().import_trait_associated_functions() + && !this.features.import_trait_associated_functions() { feature_err( this.tcx.sess, @@ -822,8 +822,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { continue; }; - if module.is_trait() && !self.tcx.features().import_trait_associated_functions() - { + if module.is_trait() && !self.features.import_trait_associated_functions() { feature_err( self.tcx.sess, sym::import_trait_associated_functions, @@ -1487,7 +1486,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If importing of trait asscoiated items is enabled, an also find an // `Enum`, then note that inherent associated items cannot be imported. - let note = if self.tcx.features().import_trait_associated_functions() + let note = if self.features.import_trait_associated_functions() && let PathResult::Module(ModuleOrUniformRoot::Module(m)) = path_res && let Some(Res::Def(DefKind::Enum, _)) = m.res() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bf53b891a08f1..479af1582fd6f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1664,7 +1664,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; // We'll ban these with a `ConstParamTy` rib, so just clear these ribs for better // diagnostics, so we don't mention anything about const param tys having generics at all. - if !self.r.tcx.features().generic_const_parameter_types() { + if !self.r.features.generic_const_parameter_types() { forward_ty_ban_rib_const_param_ty.bindings.clear(); forward_const_ban_rib_const_param_ty.bindings.clear(); } @@ -1701,7 +1701,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.ribs[TypeNS].push(forward_ty_ban_rib_const_param_ty); this.ribs[ValueNS].push(forward_const_ban_rib_const_param_ty); - if this.r.tcx.features().generic_const_parameter_types() { + if this.r.features.generic_const_parameter_types() { this.visit_ty(ty) } else { this.ribs[TypeNS].push(Rib::new(RibKind::ConstParamTy)); @@ -1812,8 +1812,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } LifetimeRibKind::ImplTrait => { - if self.r.tcx.features().anonymous_lifetime_in_impl_trait() - { + if self.r.features.anonymous_lifetime_in_impl_trait() { None } else { Some(LifetimeUseSet::Many) @@ -2991,7 +2990,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item( - if self.r.tcx.features().generic_const_items() { + if self.r.features.generic_const_items() { HasGenericParams::Yes(generics.span) } else { HasGenericParams::No @@ -3008,7 +3007,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeRibKind::Elided(LifetimeRes::Static), |this| { if rhs_kind.is_type_const() - && !this.r.tcx.features().generic_const_parameter_types() + && !this.r.features.generic_const_parameter_types() { this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { @@ -3255,7 +3254,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { RibKind::Normal => { // FIXME(non_lifetime_binders): Stop special-casing // const params to error out here. - if self.r.tcx.features().non_lifetime_binders() + if self.r.features.non_lifetime_binders() && matches!(param.kind, GenericParamKind::Type { .. }) { Res::Def(def_kind, def_id.to_def_id()) @@ -3409,7 +3408,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| { this.visit_generics(generics); if rhs_kind.is_type_const() - && !this.r.tcx.features().generic_const_parameter_types() + && !this.r.features.generic_const_parameter_types() { this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { @@ -5038,10 +5037,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let tcx = self.r.tcx(); let gate_err_sym_msg = match prim { - PrimTy::Float(FloatTy::F16) if !tcx.features().f16() => { + PrimTy::Float(FloatTy::F16) if !self.r.features.f16() => { Some((sym::f16, "the type `f16` is unstable")) } - PrimTy::Float(FloatTy::F128) if !tcx.features().f128() => { + PrimTy::Float(FloatTy::F128) if !self.r.features.f128() => { Some((sym::f128, "the type `f128` is unstable")) } _ => None, @@ -5196,8 +5195,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { AnonConstKind::FieldDefaultValue => ConstantHasGenerics::Yes, AnonConstKind::InlineConst => ConstantHasGenerics::Yes, AnonConstKind::ConstArg(_) => { - if self.r.tcx.features().generic_const_exprs() - || self.r.tcx.features().min_generic_const_args() + if self.r.features.generic_const_exprs() + || self.r.features.min_generic_const_args() || is_trivial_const_arg { ConstantHasGenerics::Yes diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 95fdf8124a225..045e0ff523c7d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1775,8 +1775,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the // benefits of including them here outweighs the small number of false positives. Some(Res::Def(DefKind::Struct | DefKind::Enum, _)) - if self.r.tcx.features().adt_const_params() - || self.r.tcx.features().min_adt_const_params() => + if self.r.features.adt_const_params() || self.r.features.min_adt_const_params() => { Applicability::MaybeIncorrect } @@ -3977,7 +3976,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }) .emit(), NoConstantGenericsReason::NonTrivialConstArg => { - assert!(!self.r.tcx.features().generic_const_exprs()); + assert!(!self.r.features.generic_const_exprs()); self.r .dcx() .create_err(diagnostics::ParamInNonTrivialAnonConst { @@ -3985,8 +3984,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { name: lifetime_ref.ident.name, param_kind: diagnostics::ParamKindInNonTrivialAnonConst::Lifetime, help: self.r.tcx.sess.is_nightly_build(), - is_gca: self.r.tcx.features().generic_const_args(), - help_gca: self.r.tcx.features().generic_const_args(), + is_gca: self.r.features.generic_const_args(), + help_gca: self.r.features.generic_const_args(), }) .emit() } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 061471ccc97e0..1f1884ea0cbe2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -50,7 +50,7 @@ use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; use rustc_data_structures::unord::{UnordItems, UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; -use rustc_feature::BUILTIN_ATTRIBUTES; +use rustc_feature::{BUILTIN_ATTRIBUTES, Features}; use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{ @@ -1550,7 +1550,8 @@ pub struct Resolver<'ra, 'tcx> { impl_trait_names: FxHashMap = default::fx_hash_map(), /// Stores `#[diagnostic::on_unknown]` attributes placed on module declarations. - on_unknown_data: FxHashMap, + on_unknown_data: FxHashMap = default::fx_hash_map(), + features: &'tcx Features, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1808,11 +1809,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let registered_tools = tcx.registered_tools(()); let edition = tcx.sess.edition(); - let mut on_unknown_data = default::fx_hash_map(); - if let Some(directive) = OnUnknownData::from_attrs(tcx, attrs) { - on_unknown_data.insert(CRATE_DEF_ID, directive); - } - let mut resolver = Resolver { tcx, @@ -1880,10 +1876,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span, disambiguators: Default::default(), delegation_infos: Default::default(), - on_unknown_data, + features: tcx.features(), .. }; + if let Some(directive) = OnUnknownData::from_attrs(&resolver, attrs) { + resolver.on_unknown_data.insert(CRATE_DEF_ID, directive); + } + let root_parent_scope = ParentScope::module(graph_root, resolver.arenas); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); resolver.feed_visibility(crate_feed, Visibility::Public); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index fade23f9cf308..595c2fdf011dd 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -699,7 +699,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We are trying to avoid reporting this error if other related errors were reported. - if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes() { + if res != Res::Err && inner_attr && !self.features.custom_inner_attributes() { let is_macro = match res { Res::Def(..) => true, Res::NonMacroAttr(..) => false, @@ -727,8 +727,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let [namespace, attribute, ..] = &*path.segments && namespace.ident.name == sym::diagnostic && !DIAGNOSTIC_ATTRIBUTES.iter().any(|(attr, feature)| { - attribute.ident.name == *attr - && feature.is_none_or(|f| self.tcx.features().enabled(f)) + attribute.ident.name == *attr && feature.is_none_or(|f| self.features.enabled(f)) }) { let name = attribute.ident.name; @@ -750,7 +749,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let candidates = DIAGNOSTIC_ATTRIBUTES .iter() .filter_map(|(attr, feature)| { - feature.is_none_or(|f| self.tcx.features().enabled(f)).then_some(*attr) + feature.is_none_or(|f| self.features.enabled(f)).then_some(*attr) }) .collect::>(); @@ -1112,7 +1111,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let feature = stability.feature; let is_allowed = - |feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature); + |feature| self.features.enabled(feature) || span.allows_unstable(feature); let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature)); if !is_allowed(feature) && !allowed_by_implication { stability::report_unstable( @@ -1242,7 +1241,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> SyntaxExtension { let mut ext = compile_declarative_macro( self.tcx.sess, - self.tcx.features(), + self.features, macro_def, ident, attrs, From 4fab41a129a2e94c3ca1ccbedba063d6d7ab389f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 23 Jun 2026 17:29:04 +0200 Subject: [PATCH 112/116] Update `rustc-literal-escaper` version to `0.0.8` --- Cargo.lock | 4 ++-- compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_proc_macro/Cargo.toml | 2 +- library/Cargo.lock | 4 ++-- library/proc_macro/Cargo.toml | 2 +- src/tools/clippy/clippy_dev/Cargo.toml | 2 +- src/tools/lint-docs/Cargo.toml | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6784840c8c2b..050af37eba8f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3561,9 +3561,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-literal-escaper" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198" +checksum = "bfe6f213fb658c8fb95baabd5420393438cf5a98d707f5dd701d9197c705f71e" [[package]] name = "rustc-main" diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index a09c36efe01f6..c60f666d3bfad 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.6" -rustc-literal-escaper = "0.0.7" +rustc-literal-escaper = "0.0.8" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 22ec84231af49..768a9546cccd4 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.7" +rustc-literal-escaper = "0.0.8" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 10b41a39c3bf2..e6922a5f2c919 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.7" +rustc-literal-escaper = "0.0.8" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 54c765075113e..e31bb4efe363d 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -16,7 +16,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.7" +rustc-literal-escaper = "0.0.8" # tidy-alphabetical-end [features] diff --git a/library/Cargo.lock b/library/Cargo.lock index 99e9765171c4a..c30ed6dc30c55 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "rustc-literal-escaper" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198" +checksum = "bfe6f213fb658c8fb95baabd5420393438cf5a98d707f5dd701d9197c705f71e" dependencies = [ "rustc-std-workspace-core", ] diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 1e5046ca61c39..286080e1bea2e 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -9,7 +9,7 @@ std = { path = "../std" } # `core` when resolving doc links. Without this line a different `core` will be # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } -rustc-literal-escaper = { version = "0.0.7", features = ["rustc-dep-of-std"] } +rustc-literal-escaper = { version = "0.0.8", features = ["rustc-dep-of-std"] } [features] default = ["rustc-dep-of-std"] diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index 49dc5c9f10a89..a11abc8d7cc4c 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -10,7 +10,7 @@ clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.8" -rustc-literal-escaper = "0.0.7" +rustc-literal-escaper = "0.0.8" walkdir = "2.3" [package.metadata.rust-analyzer] diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index ab99eb8ea3b72..2d7d6a6fc5e79 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc-literal-escaper = "0.0.7" +rustc-literal-escaper = "0.0.8" serde_json = "1.0.57" tempfile = "3.1.0" walkdir = "2.3.1" From bf86b324fbb815f45c0d983c653697d371e5c649 Mon Sep 17 00:00:00 2001 From: Yilin Chen <1479826151@qq.com> Date: Wed, 24 Jun 2026 00:45:52 +0800 Subject: [PATCH 113/116] Fix incorrect unsafe debug assertion in unchecked_div_exact --- library/core/src/num/int_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 34f16184e4ec3..f5508b1a4463d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1181,7 +1181,7 @@ macro_rules! int_impl { ( lhs: $SelfT = self, rhs: $SelfT = rhs, - ) => rhs > 0 && lhs % rhs == 0 && (lhs != <$SelfT>::MIN || rhs != -1), + ) => rhs != 0 && lhs % rhs == 0 && (lhs != <$SelfT>::MIN || rhs != -1), ); // SAFETY: Same precondition unsafe { intrinsics::exact_div(self, rhs) } From 4b62a303975c6a8ad0f2f57beb354628116fac19 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 23 Jun 2026 14:40:08 -0400 Subject: [PATCH 114/116] Add tracking issue --- library/core/src/char/methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 8e25320b6b268..8517df4da2afc 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1139,7 +1139,7 @@ impl char { /// [`UnicodeData.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt /// #[must_use] - #[unstable(feature = "char_unassigned_private_use", issue = "none")] + #[unstable(feature = "char_unassigned_private_use", issue = "158322")] #[inline] pub const fn is_private_use(self) -> bool { // According to @@ -1213,7 +1213,7 @@ impl char { /// /* assert!(!'\u{7AAAA}'.is_assigned()); */ /// ``` #[must_use] - #[unstable(feature = "char_unassigned_private_use", issue = "none")] + #[unstable(feature = "char_unassigned_private_use", issue = "158322")] #[inline] pub fn is_assigned(self) -> bool { match self { From 2dad1f8fecea0127b95ea5592b931e16e3a349af Mon Sep 17 00:00:00 2001 From: tison Date: Tue, 23 Jun 2026 19:22:06 +0000 Subject: [PATCH 115/116] FromUtf8Error::into_utf8_lossy better example and suggest use --- library/alloc/src/string.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 229514803bf6a..eb00db4568b63 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2239,15 +2239,33 @@ impl FromUtf8Error { /// invalid sequences, and [`String::from_utf8_lossy_owned`] for the /// `String` function which corresponds to this function. /// + /// This is useful in conjunction with [`String::from_utf8`] when you need + /// to branch on whether the bytes are valid UTF-8, but still want to + /// recover a lossily converted `String` in the error case. Use + /// [`String::from_utf8_lossy_owned`] if you always need a lossily converted + /// `String`. + /// + /// Since the original [`String::from_utf8`] error records where validation + /// stopped, this method does not need to re-check the already valid prefix + /// of the byte sequence. + /// /// # Examples /// /// ``` /// #![feature(string_from_utf8_lossy_owned)] /// // some invalid bytes /// let input: Vec = b"Hello \xF0\x90\x80World".into(); - /// let output = String::from_utf8(input).unwrap_or_else(|e| e.into_utf8_lossy()); + /// + /// let (output, had_invalid_utf8) = match String::from_utf8(input) { + /// Ok(output) => (output, false), + /// Err(error) => { + /// // The bytes were not valid UTF-8, but we can still recover a string. + /// (error.into_utf8_lossy(), true) + /// } + /// }; /// /// assert_eq!(String::from("Hello �World"), output); + /// assert!(had_invalid_utf8); /// ``` #[must_use] #[cfg(not(no_global_oom_handling))] From f44639116370bbf5c793c4771be8992af9e2b1be Mon Sep 17 00:00:00 2001 From: Cathal Mullan Date: Wed, 24 Jun 2026 00:49:16 +0100 Subject: [PATCH 116/116] Stop excluding `stdarch` test crates from `rust-src` --- src/bootstrap/src/core/build_steps/dist.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b0feea13b0485..114387d963a6d 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1201,11 +1201,6 @@ impl Step for Src { // not needed and contains symlinks which rustup currently // chokes on when unpacking. "library/backtrace/crates", - // these are 30MB combined and aren't necessary for building - // the standard library. - "library/stdarch/Cargo.toml", - "library/stdarch/crates/stdarch-verify", - "library/stdarch/crates/intrinsic-test", ], &dst_src, );