From 47b138b2b89f91278b7825569b1bdad24f1eee6a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Jul 2025 18:11:07 +0200 Subject: [PATCH 01/19] Make aliases search support partial matching --- src/librustdoc/html/render/search_index.rs | 2 +- src/librustdoc/html/static/js/rustdoc.d.ts | 5 + src/librustdoc/html/static/js/search.js | 150 +++++++++++---------- 3 files changed, 83 insertions(+), 74 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index aff8684ee3a09..ef0a8361fd90a 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -116,7 +116,7 @@ pub(crate) fn build_index( // Set up alias indexes. for (i, item) in cache.search_index.iter().enumerate() { for alias in &item.aliases[..] { - aliases.entry(alias.as_str().to_lowercase()).or_default().push(i); + aliases.entry(alias.to_string()).or_default().push(i); } } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index ca2512e5ab688..9ce24d1c06f60 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -227,6 +227,11 @@ declare namespace rustdoc { path: string, ty: number, type: FunctionSearchType | null, + descIndex: number, + bitIndex: number, + implDisambiguator: String | null, + is_alias?: boolean, + original?: Row, } /** diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 15cad31f555a6..2caf214ff73d4 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -830,7 +830,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) { */ function makePrimitiveElement(name, extra) { return Object.assign({ - name: name, + name, id: null, fullPath: [name], pathWithoutLast: [], @@ -1483,6 +1483,7 @@ class DocSearch { */ this.assocTypeIdNameMap = new Map(); this.ALIASES = new Map(); + this.FOUND_ALIASES = new Set(); this.rootPath = rootPath; this.searchState = searchState; @@ -2030,6 +2031,8 @@ class DocSearch { // normalized names, type signature objects and fingerprints, and aliases. id = 0; + /** @type {Array<[string, { [key: string]: Array }, number]>} */ + const allAliases = []; for (const [crate, crateCorpus] of rawSearchIndex) { // a string representing the lengths of each description shard // a string representing the list of function types @@ -2178,10 +2181,10 @@ class DocSearch { paths[i] = { ty, name, path, exactPath, unboxFlag }; } - // convert `item*` into an object form, and construct word indices. + // Convert `item*` into an object form, and construct word indices. // - // before any analysis is performed lets gather the search terms to - // search against apart from the rest of the data. This is a quick + // Before any analysis is performed, let's gather the search terms to + // search against apart from the rest of the data. This is a quick // operation that is cached for the life of the page state so that // all other search operations have access to this cached data for // faster analysis operations @@ -2269,29 +2272,58 @@ class DocSearch { } if (aliases) { - const currentCrateAliases = new Map(); - this.ALIASES.set(crate, currentCrateAliases); - for (const alias_name in aliases) { - if (!Object.prototype.hasOwnProperty.call(aliases, alias_name)) { - continue; - } - - /** @type{number[]} */ - let currentNameAliases; - if (currentCrateAliases.has(alias_name)) { - currentNameAliases = currentCrateAliases.get(alias_name); - } else { - currentNameAliases = []; - currentCrateAliases.set(alias_name, currentNameAliases); - } - for (const local_alias of aliases[alias_name]) { - currentNameAliases.push(local_alias + currentIndex); - } - } + // We need to add the aliases in `searchIndex` after we finished filling it + // to not mess up indexes. + allAliases.push([crate, aliases, currentIndex]); } currentIndex += itemTypes.length; this.searchState.descShards.set(crate, descShardList); } + + for (const [crate, aliases, index] of allAliases) { + for (const [alias_name, alias_refs] of Object.entries(aliases)) { + if (!this.ALIASES.has(crate)) { + this.ALIASES.set(crate, new Map()); + } + const word = alias_name.toLowerCase(); + const crate_alias_map = this.ALIASES.get(crate); + if (!crate_alias_map.has(word)) { + crate_alias_map.set(word, []); + } + const aliases_map = crate_alias_map.get(word); + + const normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, ""); + for (const alias of alias_refs) { + const originalIndex = alias + index; + const original = searchIndex[originalIndex]; + /** @type {rustdoc.Row} */ + const row = { + crate, + name: alias_name, + normalizedName, + is_alias: true, + ty: original.ty, + type: original.type, + paramNames: [], + word, + id, + parent: undefined, + original, + path: "", + implDisambiguator: original.implDisambiguator, + // Needed to load the description of the original item. + // @ts-ignore + descShard: original.descShard, + descIndex: original.descIndex, + bitIndex: original.bitIndex, + }; + aliases_map.push(row); + this.nameTrie.insert(normalizedName, id, this.tailTable); + id += 1; + searchIndex.push(row); + } + } + } // Drop the (rather large) hash table used for reusing function items this.TYPES_POOL = new Map(); return searchIndex; @@ -2536,6 +2568,8 @@ class DocSearch { parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) + parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0); const maxEditDistance = Math.floor(queryLen / 3); + // We reinitialize the `FOUND_ALIASES` map. + this.FOUND_ALIASES.clear(); /** * @type {Map} @@ -2695,6 +2729,10 @@ class DocSearch { const buildHrefAndPath = item => { let displayPath; let href; + if (item.is_alias) { + this.FOUND_ALIASES.add(item.word); + item = item.original; + } const type = itemTypes[item.ty]; const name = item.name; let path = item.path; @@ -3198,8 +3236,7 @@ class DocSearch { result.item = this.searchIndex[result.id]; result.word = this.searchIndex[result.id].word; if (isReturnTypeQuery) { - // we are doing a return-type based search, - // deprioritize "clone-like" results, + // We are doing a return-type based search, deprioritize "clone-like" results, // ie. functions that also take the queried type as an argument. const resultItemType = result.item && result.item.type; if (!resultItemType) { @@ -4259,28 +4296,13 @@ class DocSearch { return false; } - // this does not yet have a type in `rustdoc.d.ts`. - // @ts-expect-error - function createAliasFromItem(item) { - return { - crate: item.crate, - name: item.name, - path: item.path, - descShard: item.descShard, - descIndex: item.descIndex, - exactPath: item.exactPath, - ty: item.ty, - parent: item.parent, - type: item.type, - is_alias: true, - bitIndex: item.bitIndex, - implDisambiguator: item.implDisambiguator, - }; - } - // @ts-expect-error const handleAliases = async(ret, query, filterCrates, currentCrate) => { const lowerQuery = query.toLowerCase(); + if (this.FOUND_ALIASES.has(lowerQuery)) { + return; + } + this.FOUND_ALIASES.add(lowerQuery); // We separate aliases and crate aliases because we want to have current crate // aliases to be before the others in the displayed results. // @ts-expect-error @@ -4292,7 +4314,7 @@ class DocSearch { && this.ALIASES.get(filterCrates).has(lowerQuery)) { const query_aliases = this.ALIASES.get(filterCrates).get(lowerQuery); for (const alias of query_aliases) { - aliases.push(createAliasFromItem(this.searchIndex[alias])); + aliases.push(alias); } } } else { @@ -4302,7 +4324,7 @@ class DocSearch { const pushTo = crate === currentCrate ? crateAliases : aliases; const query_aliases = crateAliasesIndex.get(lowerQuery); for (const alias of query_aliases) { - pushTo.push(createAliasFromItem(this.searchIndex[alias])); + pushTo.push(alias); } } } @@ -4310,9 +4332,9 @@ class DocSearch { // @ts-expect-error const sortFunc = (aaa, bbb) => { - if (aaa.path < bbb.path) { + if (aaa.original.path < bbb.original.path) { return 1; - } else if (aaa.path === bbb.path) { + } else if (aaa.original.path === bbb.original.path) { return 0; } return -1; @@ -4321,21 +4343,10 @@ class DocSearch { crateAliases.sort(sortFunc); aliases.sort(sortFunc); - // @ts-expect-error - const fetchDesc = alias => { - // @ts-expect-error - return this.searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex) ? - "" : this.searchState.loadDesc(alias); - }; - const [crateDescs, descs] = await Promise.all([ - // @ts-expect-error - Promise.all(crateAliases.map(fetchDesc)), - Promise.all(aliases.map(fetchDesc)), - ]); - // @ts-expect-error const pushFunc = alias => { - alias.alias = query; + // Cloning `alias` to prevent its fields to be updated. + alias = {...alias}; const res = buildHrefAndPath(alias); alias.displayPath = pathSplitter(res[0]); alias.fullPath = alias.displayPath + alias.name; @@ -4347,16 +4358,8 @@ class DocSearch { } }; - aliases.forEach((alias, i) => { - // @ts-expect-error - alias.desc = descs[i]; - }); aliases.forEach(pushFunc); // @ts-expect-error - crateAliases.forEach((alias, i) => { - alias.desc = crateDescs[i]; - }); - // @ts-expect-error crateAliases.forEach(pushFunc); }; @@ -4802,7 +4805,7 @@ async function addTab(array, query, display) { output.className = "search-results " + extraClass; const lis = Promise.all(array.map(async item => { - const name = item.name; + const name = item.is_alias ? item.original.name : item.name; const type = itemTypes[item.ty]; const longType = longItemTypes[item.ty]; const typeName = longType.length !== 0 ? `${longType}` : "?"; @@ -4822,7 +4825,7 @@ async function addTab(array, query, display) { let alias = " "; if (item.is_alias) { alias = `
\ -${item.alias} - see \ +${item.name} - see \
`; } resultName.insertAdjacentHTML( @@ -5201,6 +5204,7 @@ function registerSearchEvents() { if (searchState.input.value.length === 0) { searchState.hideResults(); } else { + // @ts-ignore searchState.timeout = setTimeout(search, 500); } }; @@ -5842,8 +5846,8 @@ Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new In // be called ONLY when the whole file has been parsed and loaded. // @ts-expect-error -function initSearch(searchIndx) { - rawSearchIndex = searchIndx; +function initSearch(searchIndex) { + rawSearchIndex = searchIndex; if (typeof window !== "undefined") { // @ts-expect-error docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState); From b0bf51f9a9323ca5abf595c6d0653d60fe68ee24 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Jul 2025 21:07:55 +0200 Subject: [PATCH 02/19] Update rustdoc search tester to new alias output --- src/tools/rustdoc-js/tester.js | 71 ++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index f70fc917770c6..0baa179e16b2d 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -28,7 +28,14 @@ function readFile(filePath) { } function contentToDiffLine(key, value) { - return `"${key}": "${value}",`; + if (typeof value === "object" && !Array.isArray(value) && value !== null) { + const out = Object.entries(value) + .filter(([subKey, _]) => ["path", "name"].includes(subKey)) + .map(([subKey, subValue]) => `"${subKey}": ${JSON.stringify(subValue)}`) + .join(", "); + return `"${key}": ${out},`; + } + return `"${key}": ${JSON.stringify(value)},`; } function shouldIgnoreField(fieldName) { @@ -37,47 +44,61 @@ function shouldIgnoreField(fieldName) { fieldName === "proposeCorrectionTo"; } +function valueMapper(key, testOutput) { + const isAlias = testOutput["is_alias"]; + let value = testOutput[key]; + // To make our life easier, if there is a "parent" type, we add it to the path. + if (key === "path") { + if (testOutput["parent"] !== undefined) { + if (value.length > 0) { + value += "::" + testOutput["parent"]["name"]; + } else { + value = testOutput["parent"]["name"]; + } + } else if (testOutput["is_alias"]) { + value = valueMapper(key, testOutput["original"]); + } + } else if (isAlias && key === "alias") { + value = testOutput["name"]; + } else if (isAlias && ["name"].includes(key)) { + value = testOutput["original"][key]; + } + return value; +} + // This function is only called when no matching result was found and therefore will only display // the diff between the two items. -function betterLookingDiff(entry, data) { +function betterLookingDiff(expected, testOutput) { let output = " {\n"; - const spaces = " "; - for (const key in entry) { - if (!Object.prototype.hasOwnProperty.call(entry, key)) { + const spaces = " "; + for (const key in expected) { + if (!Object.prototype.hasOwnProperty.call(expected, key)) { continue; } - if (!data || !Object.prototype.hasOwnProperty.call(data, key)) { - output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n"; + if (!testOutput || !Object.prototype.hasOwnProperty.call(testOutput, key)) { + output += "-" + spaces + contentToDiffLine(key, expected[key]) + "\n"; continue; } - const value = data[key]; - if (value !== entry[key]) { - output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n"; + const value = valueMapper(key, testOutput); + if (value !== expected[key]) { + output += "-" + spaces + contentToDiffLine(key, expected[key]) + "\n"; output += "+" + spaces + contentToDiffLine(key, value) + "\n"; } else { - output += spaces + contentToDiffLine(key, value) + "\n"; + output += spaces + " " + contentToDiffLine(key, value) + "\n"; } } return output + " }"; } -function lookForEntry(entry, data) { - return data.findIndex(data_entry => { +function lookForEntry(expected, testOutput) { + return testOutput.findIndex(testOutputEntry => { let allGood = true; - for (const key in entry) { - if (!Object.prototype.hasOwnProperty.call(entry, key)) { + for (const key in expected) { + if (!Object.prototype.hasOwnProperty.call(expected, key)) { continue; } - let value = data_entry[key]; - // To make our life easier, if there is a "parent" type, we add it to the path. - if (key === "path" && data_entry["parent"] !== undefined) { - if (value.length > 0) { - value += "::" + data_entry["parent"]["name"]; - } else { - value = data_entry["parent"]["name"]; - } - } - if (value !== entry[key]) { + const value = valueMapper(key, testOutputEntry); + if (value !== expected[key]) { allGood = false; break; } From c079c96877fdd3977c8d5be830931ecb4f79018d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Jul 2025 21:08:18 +0200 Subject: [PATCH 03/19] Add test for aliases partial match --- tests/rustdoc-js-std/alias-lev.js | 11 +++++++++++ tests/rustdoc-js/non-english-identifier.js | 17 +++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 tests/rustdoc-js-std/alias-lev.js diff --git a/tests/rustdoc-js-std/alias-lev.js b/tests/rustdoc-js-std/alias-lev.js new file mode 100644 index 0000000000000..17f3dc25d7633 --- /dev/null +++ b/tests/rustdoc-js-std/alias-lev.js @@ -0,0 +1,11 @@ +// This test ensures that aliases are also allowed to be partially matched. + +// ignore-order + +const EXPECTED = { + // The full alias name is `getcwd`. + 'query': 'getcw', + 'others': [ + { 'path': 'std::env', 'name': 'current_dir', 'alias': 'getcwd' }, + ], +}; diff --git a/tests/rustdoc-js/non-english-identifier.js b/tests/rustdoc-js/non-english-identifier.js index f2180b4c75530..3d50bd3ee9057 100644 --- a/tests/rustdoc-js/non-english-identifier.js +++ b/tests/rustdoc-js/non-english-identifier.js @@ -115,11 +115,10 @@ const EXPECTED = [ query: '加法', others: [ { - name: "add", + name: "加法", path: "non_english_identifier", - is_alias: true, - alias: "加法", - href: "../non_english_identifier/macro.add.html" + href: "../non_english_identifier/trait.加法.html", + desc: "Add" }, { name: "add", @@ -129,11 +128,13 @@ const EXPECTED = [ href: "../non_english_identifier/fn.add.html" }, { - name: "加法", + name: "add", path: "non_english_identifier", - href: "../non_english_identifier/trait.加法.html", - desc: "Add" - }], + is_alias: true, + alias: "加法", + href: "../non_english_identifier/macro.add.html" + }, + ], in_args: [{ name: "加上", path: "non_english_identifier::加法", From 10762d5001f6abe686b14bffb83e618ec8fa2bb6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:17:40 +0000 Subject: [PATCH 04/19] Fix debuginfo-lto-alloc.rs test This should have used build-pass rather than check-pass. --- tests/ui/lto/debuginfo-lto-alloc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/lto/debuginfo-lto-alloc.rs b/tests/ui/lto/debuginfo-lto-alloc.rs index 89043275329d1..d6855f8760d52 100644 --- a/tests/ui/lto/debuginfo-lto-alloc.rs +++ b/tests/ui/lto/debuginfo-lto-alloc.rs @@ -8,8 +8,9 @@ // This test reproduces the circumstances that caused the error to appear, and checks // that compilation is successful. -//@ check-pass +//@ build-pass //@ compile-flags: --test -C debuginfo=2 -C lto=fat +//@ no-prefer-dynamic //@ incremental extern crate alloc; From 63e1074c97b60d248f86321f021871f93ba10c31 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 9 Jul 2025 14:18:37 +0200 Subject: [PATCH 05/19] Update AMDGPU data layout --- compiler/rustc_codegen_llvm/src/context.rs | 5 +++++ compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 6a23becaa96ff..34bed2a1d2a3d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -207,6 +207,11 @@ pub(crate) unsafe fn create_module<'ll>( // LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961 target_data_layout = target_data_layout.replace("e-p6:32:32-i64", "e-i64"); } + if sess.target.arch == "amdgpu" { + // LLVM 21 adds the address width for address space 8. + // See https://github.com/llvm/llvm-project/pull/139419 + target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128") + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs index f20782cabb878..0d6c6194e2694 100644 --- a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs +++ b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs @@ -3,7 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, Target, TargetMetadata, pub(crate) fn target() -> Target { Target { arch: "amdgpu".into(), - data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(), + data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(), llvm_target: "amdgcn-amd-amdhsa".into(), metadata: TargetMetadata { description: Some("AMD GPU".into()), From 12b19be741ea07934d7478bd8e450dca8f85afe5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 11 Jul 2025 10:11:03 +0200 Subject: [PATCH 06/19] Pass wasm exception model to TargetOptions This is no longer implied by -wasm-enable-eh. --- compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs | 2 ++ compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 5 ++++- tests/assembly/wasm_exceptions.rs | 1 - 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index dfde45955906c..8e82013e94ad5 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -39,6 +39,7 @@ impl OwnedTargetMachine { debug_info_compression: &CStr, use_emulated_tls: bool, args_cstr_buff: &[u8], + use_wasm_eh: bool, ) -> Result> { assert!(args_cstr_buff.len() > 0); assert!( @@ -72,6 +73,7 @@ impl OwnedTargetMachine { use_emulated_tls, args_cstr_buff.as_ptr() as *const c_char, args_cstr_buff.len(), + use_wasm_eh, ) }; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 68279008c03dd..6f8fba2a30dc3 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -15,6 +15,7 @@ use rustc_codegen_ssa::back::write::{ BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; +use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; @@ -285,6 +286,8 @@ pub(crate) fn target_machine_factory( let file_name_display_preference = sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO); + let use_wasm_eh = wants_wasm_eh(sess); + Arc::new(move |config: TargetMachineFactoryConfig| { let path_to_cstring_helper = |path: Option| -> CString { let path = path.unwrap_or_default(); @@ -321,6 +324,7 @@ pub(crate) fn target_machine_factory( &debuginfo_compression, use_emulated_tls, &args_cstr_buff, + use_wasm_eh, ) }) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0b1e632cbc42c..80a0e5c5accc2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2425,6 +2425,7 @@ unsafe extern "C" { UseEmulatedTls: bool, ArgsCstrBuff: *const c_char, ArgsCstrBuffLen: usize, + UseWasmEH: bool, ) -> *mut TargetMachine; pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index cc33764e485ad..e649978780e4c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -396,7 +396,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray, const char *SplitDwarfFile, const char *OutputObjFile, const char *DebugInfoCompression, bool UseEmulatedTls, - const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) { + const char *ArgsCstrBuff, size_t ArgsCstrBuffLen, bool UseWasmEH) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -462,6 +462,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.ThreadModel = ThreadModel::Single; } + if (UseWasmEH) + Options.ExceptionModel = ExceptionHandling::Wasm; + Options.EmitStackSizeSection = EmitStackSizeSection; if (ArgsCstrBuff != nullptr) { diff --git a/tests/assembly/wasm_exceptions.rs b/tests/assembly/wasm_exceptions.rs index f05ccfadc5858..704e8026f3f48 100644 --- a/tests/assembly/wasm_exceptions.rs +++ b/tests/assembly/wasm_exceptions.rs @@ -2,7 +2,6 @@ //@ assembly-output: emit-asm //@ compile-flags: -C target-feature=+exception-handling //@ compile-flags: -C panic=unwind -//@ compile-flags: -C llvm-args=-wasm-enable-eh #![crate_type = "lib"] #![feature(core_intrinsics)] From a65563e9cd817e2cfd75291bb97529dfb14eb451 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 14 Jul 2025 10:29:05 +0200 Subject: [PATCH 07/19] Make emit-arity-indicator.rs a no_core test The presence of `@add-core-stubs` indicates that this was already intended. --- .../sanitizer/kcfi/emit-arity-indicator.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs b/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs index b3b623b509b4b..f9966a2344690 100644 --- a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs +++ b/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs @@ -8,6 +8,14 @@ //@ min-llvm-version: 21.0.0 #![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; + +unsafe extern "C" { + safe fn add(x: i32, y: i32) -> i32; +} pub fn add_one(x: i32) -> i32 { // CHECK-LABEL: __cfi__{{.*}}7add_one{{.*}}: @@ -23,7 +31,7 @@ pub fn add_one(x: i32) -> i32 { // CHECK-NEXT: nop // CHECK-NEXT: nop // CHECK-NEXT: mov ecx, 2628068948 - x + 1 + add(x, 1) } pub fn add_two(x: i32, _y: i32) -> i32 { @@ -40,7 +48,7 @@ pub fn add_two(x: i32, _y: i32) -> i32 { // CHECK-NEXT: nop // CHECK-NEXT: nop // CHECK-NEXT: mov edx, 2505940310 - x + 2 + add(x, 2) } pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { @@ -57,5 +65,5 @@ pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK-NEXT: nop // CHECK-NEXT: nop // CHECK-NEXT: mov edx, 653723426 - f(arg) + f(arg) + add(f(arg), f(arg)) } From 15acb0e0ec849453d9db928821cecc552bb51bfd Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 18 Jul 2025 13:43:24 +0000 Subject: [PATCH 08/19] unicode-table-gen: clippy fixes --- .../src/cascading_map.rs | 14 +++++------ .../src/case_mapping.rs | 2 +- src/tools/unicode-table-generator/src/main.rs | 24 +++++++++---------- .../src/raw_emitter.rs | 23 +++++++----------- 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/tools/unicode-table-generator/src/cascading_map.rs b/src/tools/unicode-table-generator/src/cascading_map.rs index 1eb35e819c07c..78a7bba320870 100644 --- a/src/tools/unicode-table-generator/src/cascading_map.rs +++ b/src/tools/unicode-table-generator/src/cascading_map.rs @@ -21,7 +21,7 @@ impl RawEmitter { let points = ranges .iter() - .flat_map(|r| (r.start..r.end).into_iter().collect::>()) + .flat_map(|r| (r.start..r.end).collect::>()) .collect::>(); println!("there are {} points", points.len()); @@ -32,21 +32,20 @@ impl RawEmitter { // assert that there is no whitespace over the 0x3000 range. assert!(point <= 0x3000, "the highest unicode whitespace value has changed"); let high_bytes = point as usize >> 8; - let codepoints = codepoints_by_high_bytes.entry(high_bytes).or_insert_with(Vec::new); + let codepoints = codepoints_by_high_bytes.entry(high_bytes).or_default(); codepoints.push(point); } let mut bit_for_high_byte = 1u8; let mut arms = Vec::::new(); - let mut high_bytes: Vec = - codepoints_by_high_bytes.keys().map(|k| k.clone()).collect(); + let mut high_bytes: Vec = codepoints_by_high_bytes.keys().copied().collect(); high_bytes.sort(); for high_byte in high_bytes { let codepoints = codepoints_by_high_bytes.get_mut(&high_byte).unwrap(); if codepoints.len() == 1 { let ch = codepoints.pop().unwrap(); - arms.push(format!("{} => c as u32 == {:#04x}", high_byte, ch)); + arms.push(format!("{high_byte} => c as u32 == {ch:#04x}")); continue; } // more than 1 codepoint in this arm @@ -54,8 +53,7 @@ impl RawEmitter { map[(*codepoint & 0xff) as usize] |= bit_for_high_byte; } arms.push(format!( - "{} => WHITESPACE_MAP[c as usize & 0xff] & {} != 0", - high_byte, bit_for_high_byte + "{high_byte} => WHITESPACE_MAP[c as usize & 0xff] & {bit_for_high_byte} != 0" )); bit_for_high_byte <<= 1; } @@ -68,7 +66,7 @@ impl RawEmitter { writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap(); writeln!(&mut self.file, " match c as u32 >> 8 {{").unwrap(); for arm in arms { - writeln!(&mut self.file, " {},", arm).unwrap(); + writeln!(&mut self.file, " {arm},").unwrap(); } writeln!(&mut self.file, " _ => false,").unwrap(); writeln!(&mut self.file, " }}").unwrap(); diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs index 00241b7ee0eb5..9c6454492e7e0 100644 --- a/src/tools/unicode-table-generator/src/case_mapping.rs +++ b/src/tools/unicode-table-generator/src/case_mapping.rs @@ -9,7 +9,7 @@ const INDEX_MASK: u32 = 1 << 22; pub(crate) fn generate_case_mapping(data: &UnicodeData) -> String { let mut file = String::new(); - write!(file, "const INDEX_MASK: u32 = 0x{:x};", INDEX_MASK).unwrap(); + write!(file, "const INDEX_MASK: u32 = 0x{INDEX_MASK:x};").unwrap(); file.push_str("\n\n"); file.push_str(HEADER.trim_start()); file.push('\n'); diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index 415db2c4dbc05..00f8c1f6ec343 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -196,12 +196,12 @@ fn load_data() -> UnicodeData { .flat_map(|codepoints| match codepoints { Codepoints::Single(c) => c .scalar() - .map(|ch| (ch as u32..ch as u32 + 1)) + .map(|ch| ch as u32..ch as u32 + 1) .into_iter() .collect::>(), Codepoints::Range(c) => c .into_iter() - .flat_map(|c| c.scalar().map(|ch| (ch as u32..ch as u32 + 1))) + .flat_map(|c| c.scalar().map(|ch| ch as u32..ch as u32 + 1)) .collect::>(), }) .collect::>>(), @@ -236,7 +236,7 @@ fn main() { let ranges_by_property = &unicode_data.ranges; if let Some(path) = test_path { - std::fs::write(&path, generate_tests(&write_location, &ranges_by_property)).unwrap(); + std::fs::write(&path, generate_tests(&write_location, ranges_by_property)).unwrap(); } let mut total_bytes = 0; @@ -246,9 +246,9 @@ fn main() { let mut emitter = RawEmitter::new(); if property == &"White_Space" { - emit_whitespace(&mut emitter, &ranges); + emit_whitespace(&mut emitter, ranges); } else { - emit_codepoints(&mut emitter, &ranges); + emit_codepoints(&mut emitter, ranges); } modules.push((property.to_lowercase().to_string(), emitter.file)); @@ -288,7 +288,7 @@ fn main() { for line in contents.lines() { if !line.trim().is_empty() { table_file.push_str(" "); - table_file.push_str(&line); + table_file.push_str(line); } table_file.push('\n'); } @@ -312,7 +312,7 @@ fn version() -> String { let start = readme.find(prefix).unwrap() + prefix.len(); let end = readme.find(" of the Unicode Standard.").unwrap(); let version = - readme[start..end].split('.').map(|v| v.parse::().expect(&v)).collect::>(); + readme[start..end].split('.').map(|v| v.parse::().expect(v)).collect::>(); let [major, minor, micro] = [version[0], version[1], version[2]]; out.push_str(&format!("({major}, {minor}, {micro});\n")); @@ -320,7 +320,7 @@ fn version() -> String { } fn fmt_list(values: impl IntoIterator) -> String { - let pieces = values.into_iter().map(|b| format!("{:?}, ", b)).collect::>(); + let pieces = values.into_iter().map(|b| format!("{b:?}, ")).collect::>(); let mut out = String::new(); let mut line = String::from("\n "); for piece in pieces { @@ -348,7 +348,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec>)]) -> String s.push_str("\nfn main() {\n"); for (property, ranges) in ranges { - s.push_str(&format!(r#" println!("Testing {}");"#, property)); + s.push_str(&format!(r#" println!("Testing {property}");"#)); s.push('\n'); s.push_str(&format!(" {}_true();\n", property.to_lowercase())); s.push_str(&format!(" {}_false();\n", property.to_lowercase())); @@ -373,7 +373,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec>)]) -> String s.push_str(" }\n\n"); } - s.push_str("}"); + s.push('}'); s } @@ -388,7 +388,7 @@ fn generate_asserts(s: &mut String, property: &str, points: &[u32], truthy: bool range.start, )); } else { - s.push_str(&format!(" for chn in {:?}u32 {{\n", range)); + s.push_str(&format!(" for chn in {range:?}u32 {{\n")); s.push_str(&format!( " assert!({}unicode_data::{}::lookup(std::char::from_u32(chn).unwrap()), \"{{:?}}\", chn);\n", if truthy { "" } else { "!" }, @@ -439,7 +439,7 @@ fn merge_ranges(ranges: &mut Vec>) { let mut last_end = None; for range in ranges { if let Some(last) = last_end { - assert!(range.start > last, "{:?}", range); + assert!(range.start > last, "{range:?}"); } last_end = Some(range.end); } diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index ee94d3c93a6cb..e1e77af9283d8 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -156,10 +156,10 @@ pub fn emit_codepoints(emitter: &mut RawEmitter, ranges: &[Range]) { emitter.blank_line(); let mut bitset = emitter.clone(); - let bitset_ok = bitset.emit_bitset(&ranges).is_ok(); + let bitset_ok = bitset.emit_bitset(ranges).is_ok(); let mut skiplist = emitter.clone(); - skiplist.emit_skiplist(&ranges); + skiplist.emit_skiplist(ranges); if bitset_ok && bitset.bytes_used <= skiplist.bytes_used { *emitter = bitset; @@ -174,7 +174,7 @@ pub fn emit_whitespace(emitter: &mut RawEmitter, ranges: &[Range]) { emitter.blank_line(); let mut cascading = emitter.clone(); - cascading.emit_cascading_map(&ranges); + cascading.emit_cascading_map(ranges); *emitter = cascading; emitter.desc = String::from("cascading"); } @@ -311,10 +311,9 @@ impl Canonicalized { } } } - assert!( - unique_mapping - .insert(to, UniqueMapping::Canonical(canonical_words.len())) - .is_none() + assert_eq!( + unique_mapping.insert(to, UniqueMapping::Canonical(canonical_words.len())), + None ); canonical_words.push(to); @@ -340,14 +339,10 @@ impl Canonicalized { // We'll probably always have some slack though so this loop will still // be needed. for &w in unique_words { - if !unique_mapping.contains_key(&w) { - assert!( - unique_mapping - .insert(w, UniqueMapping::Canonical(canonical_words.len())) - .is_none() - ); + unique_mapping.entry(w).or_insert_with(|| { canonical_words.push(w); - } + UniqueMapping::Canonical(canonical_words.len()) + }); } assert_eq!(canonicalized_words.len() + canonical_words.len(), unique_words.len()); assert_eq!(unique_mapping.len(), unique_words.len()); From 09593059867b066d23776e00a2ce31c370ec9277 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 18 Jul 2025 13:45:33 +0000 Subject: [PATCH 09/19] unicode-table-gen: edition 2024 --- src/tools/unicode-table-generator/Cargo.toml | 2 +- src/tools/unicode-table-generator/src/raw_emitter.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/unicode-table-generator/Cargo.toml b/src/tools/unicode-table-generator/Cargo.toml index f8a500922d052..3ca6e9e316f1d 100644 --- a/src/tools/unicode-table-generator/Cargo.toml +++ b/src/tools/unicode-table-generator/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "unicode-table-generator" version = "0.1.0" -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index e1e77af9283d8..e9e0efc459442 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -272,7 +272,7 @@ impl Canonicalized { // for canonical when possible. while let Some((&to, _)) = mappings .iter() - .find(|(&to, _)| to == 0) + .find(|&(&to, _)| to == 0) .or_else(|| mappings.iter().max_by_key(|m| m.1.len())) { // Get the mapping with the most entries. Currently, no mapping can From b0073d92fbb5402ff7bed69f28aab4b34b05a9df Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 18 Jul 2025 13:51:18 +0000 Subject: [PATCH 10/19] unicode-table-gen: more clippy fixes --- src/tools/unicode-table-generator/src/main.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index 00f8c1f6ec343..6cdb82a87bdff 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -160,15 +160,15 @@ fn load_data() -> UnicodeData { .push(Codepoints::Single(row.codepoint)); } - if let Some(mapped) = row.simple_lowercase_mapping { - if mapped != row.codepoint { - to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0)); - } + if let Some(mapped) = row.simple_lowercase_mapping + && mapped != row.codepoint + { + to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0)); } - if let Some(mapped) = row.simple_uppercase_mapping { - if mapped != row.codepoint { - to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0)); - } + if let Some(mapped) = row.simple_uppercase_mapping + && mapped != row.codepoint + { + to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0)); } } From 8a8717e971dbdc6155506a4332e9ce8ef9151caa Mon Sep 17 00:00:00 2001 From: Luigi Sartor Piucco Date: Sun, 20 Apr 2025 18:43:54 -0300 Subject: [PATCH 11/19] fix: don't panic on volatile access to null According to https://discourse.llvm.org/t/rfc-volatile-access-to-non-dereferenceable-memory-may-be-well-defined/86303/4, LLVM allows volatile operations on null and handles it correctly. This should be allowed in Rust as well, because I/O memory may be hard-coded to address 0 in some cases, like the AVR chip ATtiny1626. A test case that ensured a failure when passing null to volatile was removed, since it's now valid. Due to the addition of `maybe_is_aligned` to `ub_checks`, `maybe_is_aligned_and_not_null` was refactored to use it. docs: revise restrictions on volatile operations A distinction between usage on Rust memory vs. non-Rust memory was introduced. Documentation was reworded to explain what that means, and make explicit that: - No trapping can occur from volatile operations; - On Rust memory, all safety rules must be respected; - On Rust memory, the primary difference from regular access is that volatile always involves a memory dereference; - On Rust memory, the only data affected by an operation is the one pointed to in the argument(s) of the function; - On Rust memory, provenance follows the same rules as non-volatile access; - On non-Rust memory, any address known to not contain Rust memory is valid (including 0 and usize::MAX); - On non-Rust memory, no Rust memory may be affected (it is implicit that any other non-Rust memory may be affected, though, even if not referenced by the pointer). This should be relevant when, for example, reading register A causes a flag to change in register B, or writing to A causes B to change in some way. Everything affected mustn't be inside an allocation. - On non-Rust memory, provenance is irrelevant and a pointer with none can be used in a valid way. fix: don't lint null as UB for volatile Also remove a now-unneeded `allow` line. fix: additional wording nits --- compiler/rustc_lint/src/ptr_nulls.rs | 4 +- library/core/src/ptr/mod.rs | 168 ++++++++++-------- library/core/src/ub_checks.rs | 18 +- tests/ui/lint/invalid_null_args.rs | 5 +- tests/ui/lint/invalid_null_args.stderr | 58 ++---- tests/ui/precondition-checks/read_volatile.rs | 6 +- .../ui/precondition-checks/write_volatile.rs | 6 +- 7 files changed, 127 insertions(+), 138 deletions(-) diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 826bce2c31506..b2fa0fba76d98 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -160,12 +160,10 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { let (arg_indices, are_zsts_allowed): (&[_], _) = match diag_name { sym::ptr_read | sym::ptr_read_unaligned - | sym::ptr_read_volatile | sym::ptr_replace | sym::ptr_write | sym::ptr_write_bytes - | sym::ptr_write_unaligned - | sym::ptr_write_volatile => (&[0], true), + | sym::ptr_write_unaligned => (&[0], true), sym::slice_from_raw_parts | sym::slice_from_raw_parts_mut => (&[0], false), sym::ptr_copy | sym::ptr_copy_nonoverlapping diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index fe8c6f830341c..dbe3999b4a433 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -28,7 +28,8 @@ //! undefined behavior to perform two concurrent accesses to the same location from different //! threads unless both accesses only read from memory. Notice that this explicitly //! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot -//! be used for inter-thread synchronization. +//! be used for inter-thread synchronization, regardless of whether they are acting on +//! Rust memory or not. //! * The result of casting a reference to a pointer is valid for as long as the //! underlying allocation is live and no reference (just raw pointers) is used to //! access the same memory. That is, reference and pointer accesses cannot be @@ -114,6 +115,10 @@ //! fully contiguous (i.e., has no "holes"), there is no guarantee that this //! will not change in the future. //! +//! Allocations must behave like "normal" memory: in particular, reads must not have +//! side-effects, and writes must become visible to other threads using the usual synchronization +//! primitives. +//! //! For any allocation with `base` address, `size`, and a set of //! `addresses`, the following are guaranteed: //! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base + @@ -2021,54 +2026,61 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { } } -/// Performs a volatile read of the value from `src` without moving it. This -/// leaves the memory in `src` unchanged. -/// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. -/// -/// # Notes -/// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. -/// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `read_volatile`) are noops -/// and may be ignored. -/// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// Performs a volatile read of the value from `src` without moving it. +/// +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally +/// observable events (just like syscalls, but less opaque), and are guaranteed to not be elided or +/// reordered by the compiler across other externally observable events. With this in mind, there +/// are two cases of usage that need to be distinguished: +/// +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like +/// [`read`], except for the additional guarantee that it won't be elided or reordered (see +/// above). This implies that the operation will actually access memory and not e.g. be lowered to +/// reusing data from a previous read. Other than that, all the usual rules for memory accesses +/// apply (including provenance). In particular, just like in C, whether an operation is volatile +/// has no bearing whatsoever on questions involving concurrent accesses from multiple threads. +/// Volatile accesses behave exactly like non-atomic accesses in that regard. +/// +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust +/// allocation. In this use-case, the pointer does *not* have to be [valid] for reads. This is +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special +/// semantics associated to their manipulation, and cannot be used as general purpose memory. +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics +/// of such a read are well-defined by the target hardware. The provenance of the pointer is +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It +/// can cause side-effects, but those must not affect Rust-allocated memory in any way. This +/// access is still not considered [atomic], and as such it cannot be used for inter-thread +/// synchronization. +/// +/// Note that volatile memory operations where T is a zero-sized type are noops and may be ignored. +/// +/// [allocation]: crate::ptr#allocated-object +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses /// /// # Safety /// +/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of whether `T` is +/// [`Copy`]. If `T` is not [`Copy`], using both the returned value and the value at `*src` can +/// [violate memory safety][read-ownership]. However, storing non-[`Copy`] types in volatile memory +/// is almost certainly incorrect. +/// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid] for reads. +/// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust +/// allocations and reading from that memory must: +/// - not trap, and +/// - not cause any memory inside a Rust allocation to be modified. /// /// * `src` must be properly aligned. /// -/// * `src` must point to a properly initialized value of type `T`. -/// -/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned -/// value and the value at `*src` can [violate memory safety][read-ownership]. -/// However, storing non-[`Copy`] types in volatile memory is almost certainly -/// incorrect. +/// * Reading from `src` must produce a properly initialized value of type `T`. /// /// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// [valid]: self#safety /// [read-ownership]: read#ownership-of-the-returned-value /// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `read_volatile` and any write operation to the same location -/// is undefined behavior. -/// /// # Examples /// /// Basic usage: @@ -2090,50 +2102,63 @@ pub unsafe fn read_volatile(src: *const T) -> T { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::read_volatile requires that the pointer argument is aligned and non-null", + "ptr::read_volatile requires that the pointer argument is aligned", ( addr: *const () = src as *const (), align: usize = align_of::(), - is_zst: bool = T::IS_ZST, - ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned(addr, align) ); intrinsics::volatile_load(src) } } -/// Performs a volatile write of a memory location with the given value without -/// reading or dropping the old value. -/// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. -/// -/// `write_volatile` does not drop the contents of `dst`. This is safe, but it -/// could leak allocations or resources, so care should be taken not to overwrite -/// an object that should be dropped. -/// -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the -/// location pointed to by `dst`. -/// -/// # Notes -/// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. -/// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops -/// and may be ignored. -/// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// Performs a volatile write of a memory location with the given value without reading or dropping +/// the old value. +/// +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally +/// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the +/// compiler across other externally observable events. With this in mind, there are two cases of +/// usage that need to be distinguished: +/// +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like +/// [`write`][write()], except for the additional guarantee that it won't be elided or reordered +/// (see above). This implies that the operation will actually access memory and not e.g. be +/// lowered to a register access. Other than that, all the usual rules for memory accesses apply +/// (including provenance). In particular, just like in C, whether an operation is volatile has no +/// bearing whatsoever on questions involving concurrent access from multiple threads. Volatile +/// accesses behave exactly like non-atomic accesses in that regard. +/// +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust +/// allocation. In this use-case, the pointer does *not* have to be [valid] for writes. This is +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special +/// semantics associated to their manipulation, and cannot be used as general purpose memory. +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics +/// of such a write are well-defined by the target hardware. The provenance of the pointer is +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It +/// can cause side-effects, but those must not affect Rust-allocated memory in any way. This +/// access is still not considered [atomic], and as such it cannot be used for inter-thread +/// synchronization. +/// +/// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed +/// to `write_volatile`) are noops and may be ignored. +/// +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care should be taken not to overwrite an object that should be +/// dropped when operating on Rust memory. Additionally, it does not drop `src`. Semantically, `src` +/// is moved into the location pointed to by `dst`. +/// +/// [allocation]: crate::ptr#allocated-object +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses /// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid] for writes. +/// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust +/// allocations and writing to that memory must: +/// - not trap, and +/// - not cause any memory inside a Rust allocation to be modified. /// /// * `dst` must be properly aligned. /// @@ -2141,12 +2166,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// [valid]: self#safety /// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `write_volatile` and any other operation (reading or writing) -/// on the same location is undefined behavior. -/// /// # Examples /// /// Basic usage: @@ -2170,12 +2189,11 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::write_volatile requires that the pointer argument is aligned and non-null", + "ptr::write_volatile requires that the pointer argument is aligned", ( addr: *mut () = dst as *mut (), align: usize = align_of::(), - is_zst: bool = T::IS_ZST, - ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned(addr, align) ); intrinsics::volatile_store(dst, src); } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index a7caaeb95cdba..b809294cfcee7 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -120,13 +120,25 @@ pub(crate) const fn maybe_is_aligned_and_not_null( align: usize, is_zst: bool, ) -> bool { + // This is just for safety checks so we can const_eval_select. + maybe_is_aligned(ptr, align) && (is_zst || !ptr.is_null()) +} + +/// Checks whether `ptr` is properly aligned with respect to the given alignment. +/// +/// In `const` this is approximate and can fail spuriously. It is primarily intended +/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the +/// check is anyway not executed in `const`. +#[inline] +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn maybe_is_aligned(ptr: *const (), align: usize) -> bool { // This is just for safety checks so we can const_eval_select. const_eval_select!( - @capture { ptr: *const (), align: usize, is_zst: bool } -> bool: + @capture { ptr: *const (), align: usize } -> bool: if const { - is_zst || !ptr.is_null() + true } else { - ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) + ptr.is_aligned_to(align) } ) } diff --git a/tests/ui/lint/invalid_null_args.rs b/tests/ui/lint/invalid_null_args.rs index f40f06a0d3624..ee29d622ad7b9 100644 --- a/tests/ui/lint/invalid_null_args.rs +++ b/tests/ui/lint/invalid_null_args.rs @@ -58,10 +58,9 @@ unsafe fn null_ptr() { let _a: A = ptr::read_unaligned(ptr::null_mut()); //~^ ERROR calling this function with a null pointer is undefined behavior + // These two should *not* fire the lint. let _a: A = ptr::read_volatile(ptr::null()); - //~^ ERROR calling this function with a null pointer is undefined behavior let _a: A = ptr::read_volatile(ptr::null_mut()); - //~^ ERROR calling this function with a null pointer is undefined behavior let _a: A = ptr::replace(ptr::null_mut(), v); //~^ ERROR calling this function with a null pointer is undefined behavior @@ -82,8 +81,8 @@ unsafe fn null_ptr() { ptr::write_unaligned(ptr::null_mut(), v); //~^ ERROR calling this function with a null pointer is undefined behavior + // This one should *not* fire the lint. ptr::write_volatile(ptr::null_mut(), v); - //~^ ERROR calling this function with a null pointer is undefined behavior ptr::write_bytes::(ptr::null_mut(), 42, 0); //~^ ERROR calling this function with a null pointer is undefined behavior diff --git a/tests/ui/lint/invalid_null_args.stderr b/tests/ui/lint/invalid_null_args.stderr index 11c6270cfb78e..028bd7051dcc3 100644 --- a/tests/ui/lint/invalid_null_args.stderr +++ b/tests/ui/lint/invalid_null_args.stderr @@ -164,27 +164,7 @@ LL | let _a: A = ptr::read_unaligned(ptr::null_mut()); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:61:17 - | -LL | let _a: A = ptr::read_volatile(ptr::null()); - | ^^^^^^^^^^^^^^^^^^^-----------^ - | | - | null pointer originates from here - | - = help: for more information, visit and - -error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:63:17 - | -LL | let _a: A = ptr::read_volatile(ptr::null_mut()); - | ^^^^^^^^^^^^^^^^^^^---------------^ - | | - | null pointer originates from here - | - = help: for more information, visit and - -error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:66:17 + --> $DIR/invalid_null_args.rs:65:17 | LL | let _a: A = ptr::replace(ptr::null_mut(), v); | ^^^^^^^^^^^^^---------------^^^^ @@ -194,7 +174,7 @@ LL | let _a: A = ptr::replace(ptr::null_mut(), v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:69:5 + --> $DIR/invalid_null_args.rs:68:5 | LL | ptr::swap::(ptr::null_mut(), &mut v); | ^^^^^^^^^^^^^^^---------------^^^^^^^^^ @@ -204,7 +184,7 @@ LL | ptr::swap::(ptr::null_mut(), &mut v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:71:5 + --> $DIR/invalid_null_args.rs:70:5 | LL | ptr::swap::(&mut v, ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -214,7 +194,7 @@ LL | ptr::swap::(&mut v, ptr::null_mut()); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:74:5 + --> $DIR/invalid_null_args.rs:73:5 | LL | ptr::swap_nonoverlapping::(ptr::null_mut(), &mut v, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^^^^^ @@ -224,7 +204,7 @@ LL | ptr::swap_nonoverlapping::(ptr::null_mut(), &mut v, 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:76:5 + --> $DIR/invalid_null_args.rs:75:5 | LL | ptr::swap_nonoverlapping::(&mut v, ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -234,7 +214,7 @@ LL | ptr::swap_nonoverlapping::(&mut v, ptr::null_mut(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:79:5 + --> $DIR/invalid_null_args.rs:78:5 | LL | ptr::write(ptr::null_mut(), v); | ^^^^^^^^^^^---------------^^^^ @@ -244,7 +224,7 @@ LL | ptr::write(ptr::null_mut(), v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:82:5 + --> $DIR/invalid_null_args.rs:81:5 | LL | ptr::write_unaligned(ptr::null_mut(), v); | ^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -254,17 +234,7 @@ LL | ptr::write_unaligned(ptr::null_mut(), v); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:85:5 - | -LL | ptr::write_volatile(ptr::null_mut(), v); - | ^^^^^^^^^^^^^^^^^^^^---------------^^^^ - | | - | null pointer originates from here - | - = help: for more information, visit and - -error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:88:5 + --> $DIR/invalid_null_args.rs:87:5 | LL | ptr::write_bytes::(ptr::null_mut(), 42, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^ @@ -274,7 +244,7 @@ LL | ptr::write_bytes::(ptr::null_mut(), 42, 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:93:18 + --> $DIR/invalid_null_args.rs:92:18 | LL | let _a: u8 = ptr::read(const_ptr); | ^^^^^^^^^^^^^^^^^^^^ @@ -287,7 +257,7 @@ LL | let null_ptr = ptr::null_mut(); | ^^^^^^^^^^^^^^^ error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:100:5 + --> $DIR/invalid_null_args.rs:99:5 | LL | std::slice::from_raw_parts::<()>(ptr::null(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ @@ -297,7 +267,7 @@ LL | std::slice::from_raw_parts::<()>(ptr::null(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:102:5 + --> $DIR/invalid_null_args.rs:101:5 | LL | std::slice::from_raw_parts::(ptr::null(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ @@ -307,7 +277,7 @@ LL | std::slice::from_raw_parts::(ptr::null(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:104:5 + --> $DIR/invalid_null_args.rs:103:5 | LL | std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -317,7 +287,7 @@ LL | std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0); = help: for more information, visit and error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused - --> $DIR/invalid_null_args.rs:106:5 + --> $DIR/invalid_null_args.rs:105:5 | LL | std::slice::from_raw_parts_mut::(ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -326,5 +296,5 @@ LL | std::slice::from_raw_parts_mut::(ptr::null_mut(), 0); | = help: for more information, visit and -error: aborting due to 31 previous errors +error: aborting due to 28 previous errors diff --git a/tests/ui/precondition-checks/read_volatile.rs b/tests/ui/precondition-checks/read_volatile.rs index ada8932c398ce..d858e6b939ac0 100644 --- a/tests/ui/precondition-checks/read_volatile.rs +++ b/tests/ui/precondition-checks/read_volatile.rs @@ -1,9 +1,7 @@ //@ run-fail //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::read_volatile requires -//@ revisions: null misaligned - -#![allow(invalid_null_arguments)] +//@ revisions: misaligned use std::ptr; @@ -11,8 +9,6 @@ fn main() { let src = [0u16; 2]; let src = src.as_ptr(); unsafe { - #[cfg(null)] - ptr::read_volatile(ptr::null::()); #[cfg(misaligned)] ptr::read_volatile(src.byte_add(1)); } diff --git a/tests/ui/precondition-checks/write_volatile.rs b/tests/ui/precondition-checks/write_volatile.rs index 0d5ecb014b3d9..ddc882be4323f 100644 --- a/tests/ui/precondition-checks/write_volatile.rs +++ b/tests/ui/precondition-checks/write_volatile.rs @@ -1,9 +1,7 @@ //@ run-fail //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: ptr::write_volatile requires -//@ revisions: null misaligned - -#![allow(invalid_null_arguments)] +//@ revisions: misaligned use std::ptr; @@ -11,8 +9,6 @@ fn main() { let mut dst = [0u16; 2]; let mut dst = dst.as_mut_ptr(); unsafe { - #[cfg(null)] - ptr::write_volatile(ptr::null_mut::(), 1u8); #[cfg(misaligned)] ptr::write_volatile(dst.byte_add(1), 1u16); } From 4cebbabd5ce3fdb1444cc7efdb8e07eff52b6652 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 16:47:39 +0000 Subject: [PATCH 12/19] Add implicit sized bound to trait ascription types --- .../src/hir_ty_lowering/mod.rs | 8 ++++++++ .../impl-trait/in-bindings/implicit-sized.rs | 19 +++++++++++++++++++ .../in-bindings/implicit-sized.stderr | 11 +++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/ui/impl-trait/in-bindings/implicit-sized.rs create mode 100644 tests/ui/impl-trait/in-bindings/implicit-sized.stderr 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 a5bd7c1a34aef..2a6ba31d5abb4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2489,6 +2489,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::List::empty(), PredicateFilter::All, ); + self.add_sizedness_bounds( + &mut bounds, + self_ty, + hir_bounds, + None, + None, + hir_ty.span, + ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); self_ty } diff --git a/tests/ui/impl-trait/in-bindings/implicit-sized.rs b/tests/ui/impl-trait/in-bindings/implicit-sized.rs new file mode 100644 index 0000000000000..2f16db941895a --- /dev/null +++ b/tests/ui/impl-trait/in-bindings/implicit-sized.rs @@ -0,0 +1,19 @@ +#![feature(impl_trait_in_bindings)] + +trait Trait {} +impl Trait for T {} + +fn doesnt_work() { + let x: &impl Trait = "hi"; + //~^ ERROR the size for values of type `str` cannot be known at compilation time +} + +fn works() { + let x: &(impl Trait + ?Sized) = "hi"; + // No implicit sized. + + let x: &impl Trait = &(); + // Is actually sized. +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-bindings/implicit-sized.stderr b/tests/ui/impl-trait/in-bindings/implicit-sized.stderr new file mode 100644 index 0000000000000..465a928cf86a2 --- /dev/null +++ b/tests/ui/impl-trait/in-bindings/implicit-sized.stderr @@ -0,0 +1,11 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/implicit-sized.rs:7:13 + | +LL | let x: &impl Trait = "hi"; + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From e6f283080c794609dadd2ded323d5af76c99b5e9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 17:30:00 +0000 Subject: [PATCH 13/19] Remove pretty print hack for async blocks --- compiler/rustc_middle/src/ty/print/pretty.rs | 26 +------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2eb530f328d39..9ee64df0ad065 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1210,30 +1210,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } for (assoc_item_def_id, term) in assoc_items { - // Skip printing `<{coroutine@} as Coroutine<_>>::Return` from async blocks, - // unless we can find out what coroutine return type it comes from. - let term = if let Some(ty) = term.skip_binder().as_type() - && let ty::Alias(ty::Projection, proj) = ty.kind() - && let Some(assoc) = tcx.opt_associated_item(proj.def_id) - && assoc - .trait_container(tcx) - .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine)) - && assoc.opt_name() == Some(rustc_span::sym::Return) - { - if let ty::Coroutine(_, args) = args.type_at(0).kind() { - let return_ty = args.as_coroutine().return_ty(); - if !return_ty.is_ty_var() { - return_ty.into() - } else { - continue; - } - } else { - continue; - } - } else { - term.skip_binder() - }; - if first { p!("<"); first = false; @@ -1243,7 +1219,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name())); - match term.kind() { + match term.skip_binder().kind() { TermKind::Ty(ty) => p!(print(ty)), TermKind::Const(c) => p!(print(c)), }; From 7672e4ed85916d564d38dbd3a64803a45568504d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Jul 2025 10:29:13 +0200 Subject: [PATCH 14/19] interpret: fix TypeId pointers being considered data pointers --- .../rustc_const_eval/src/interpret/memory.rs | 10 ++++------ library/core/src/any.rs | 2 +- src/tools/miri/src/alloc_addresses/mod.rs | 2 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 4 ++-- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- .../miri/tests/pass/intrinsics/type-id.rs | 19 +++++++++++++++++++ 6 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 src/tools/miri/tests/pass/intrinsics/type-id.rs diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 47228de52138e..20c8e983ceaef 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -67,8 +67,8 @@ pub enum AllocKind { LiveData, /// A function allocation (that fn ptrs point to). Function, - /// A (symbolic) vtable allocation. - VTable, + /// A "virtual" allocation, used for vtables and TypeId. + Virtual, /// A dead allocation. Dead, } @@ -950,11 +950,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { - GlobalAlloc::TypeId { .. } - | GlobalAlloc::Static { .. } - | GlobalAlloc::Memory { .. } => AllocKind::LiveData, + GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), - GlobalAlloc::VTable { .. } => AllocKind::VTable, + GlobalAlloc::VTable { .. } | GlobalAlloc::TypeId { .. } => AllocKind::Virtual, }; return AllocInfo::new(size, align, kind, mutbl); } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 39cdf6efda07a..38393379a78a7 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -783,7 +783,7 @@ impl TypeId { // This is a provenance-stripping memcpy. for (i, chunk) in self.data.iter().copied().enumerate() { - let chunk = chunk.expose_provenance().to_ne_bytes(); + let chunk = chunk.addr().to_ne_bytes(); let start = i * chunk.len(); bytes[start..(start + chunk.len())].copy_from_slice(&chunk); } diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 3cc38fa087c67..10339928ac2dd 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -157,7 +157,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.get_alloc_bytes_unchecked_raw(alloc_id)? } } - AllocKind::Function | AllocKind::VTable => { + AllocKind::Function | AllocKind::Virtual => { // Allocate some dummy memory to get a unique address for this function/vtable. let alloc_bytes = MiriAllocBytes::from_bytes( &[0u8; 1], diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 834a4b41f2245..e834fdffdd182 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -650,7 +650,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { dcx.log_protector(); } }, - AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => { // No stacked borrows on these allocations. } } @@ -1021,7 +1021,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.borrow_tracker_sb().borrow_mut().exposed_tags.insert(tag); } - AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => { // No stacked borrows on these allocations. } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index c157c69d7c843..aa92f8a8c3096 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -673,7 +673,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("Tree Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag); } - AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => { // No tree borrows on these allocations. } } diff --git a/src/tools/miri/tests/pass/intrinsics/type-id.rs b/src/tools/miri/tests/pass/intrinsics/type-id.rs new file mode 100644 index 0000000000000..123fdbdc9ceae --- /dev/null +++ b/src/tools/miri/tests/pass/intrinsics/type-id.rs @@ -0,0 +1,19 @@ +use std::any::{Any, TypeId}; + +fn main() { + let t1 = TypeId::of::(); + let t2 = TypeId::of::(); + assert_eq!(t1, t2); + let t3 = TypeId::of::(); + assert_ne!(t1, t3); + + let _ = format!("{t1:?}"); // test that we can debug-print + + let b = Box::new(0u64) as Box; + assert_eq!(*b.downcast_ref::().unwrap(), 0); + assert!(b.downcast_ref::().is_none()); + + // Get the first pointer chunk and try to make it a ZST ref. + // This used to trigger an error because TypeId allocs got misclassified as "LiveData". + let _raw_chunk = unsafe { (&raw const t1).cast::<&()>().read() }; +} From ca01e7de6fae15337df4b612869353523b3c947d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nurzhan=20Sak=C3=A9n?= Date: Mon, 7 Jul 2025 22:48:18 +0400 Subject: [PATCH 15/19] Stabilize `const_float_round_methods` --- library/core/src/num/f128.rs | 6 ------ library/core/src/num/f16.rs | 6 ------ library/core/src/num/f32.rs | 6 ------ library/core/src/num/f64.rs | 6 ------ library/coretests/tests/lib.rs | 1 - library/std/src/lib.rs | 1 - library/std/src/num/f32.rs | 12 ++++++------ library/std/src/num/f64.rs | 12 ++++++------ 8 files changed, 12 insertions(+), 38 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 4c09c930c796f..69e6c100e763a 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1448,7 +1448,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1478,7 +1477,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1514,7 +1512,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1548,7 +1545,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(self) -> f128 { intrinsics::round_ties_even_f128(self) @@ -1580,7 +1576,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1611,7 +1606,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(self) -> f128 { self - self.trunc() diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 1d98a485c4f72..b66cef03d2003 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1424,7 +1424,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1454,7 +1453,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1490,7 +1488,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1524,7 +1521,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(self) -> f16 { intrinsics::round_ties_even_f16(self) @@ -1556,7 +1552,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1587,7 +1582,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(self) -> f16 { self - self.trunc() diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index b460c7d0205bf..f8344da79ad40 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1591,7 +1591,6 @@ pub mod math { /// [`f32::floor`]: ../../../std/primitive.f32.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions @@ -1622,7 +1621,6 @@ pub mod math { #[doc(alias = "ceiling")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn ceil(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::ceilf32(x) } @@ -1657,7 +1655,6 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn round(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::roundf32(x) } @@ -1691,7 +1688,6 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn round_ties_even(x: f32) -> f32 { intrinsics::round_ties_even_f32(x) } @@ -1722,7 +1718,6 @@ pub mod math { #[doc(alias = "truncate")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn trunc(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::truncf32(x) } @@ -1752,7 +1747,6 @@ pub mod math { /// [`f32::fract`]: ../../../std/primitive.f32.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(x: f32) -> f32 { x - trunc(x) diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 3cd079b84eb4c..93da63c896e23 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1589,7 +1589,6 @@ pub mod math { /// [`f64::floor`]: ../../../std/primitive.f64.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1619,7 +1618,6 @@ pub mod math { #[inline] #[doc(alias = "ceiling")] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1654,7 +1652,6 @@ pub mod math { /// [`f64::round`]: ../../../std/primitive.f64.html#method.round #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1688,7 +1685,6 @@ pub mod math { /// [`f64::round_ties_even`]: ../../../std/primitive.f64.html#method.round_ties_even #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(x: f64) -> f64 { intrinsics::round_ties_even_f64(x) @@ -1719,7 +1715,6 @@ pub mod math { #[inline] #[doc(alias = "truncate")] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1750,7 +1745,6 @@ pub mod math { /// [`f64::fract`]: ../../../std/primitive.f64.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(x: f64) -> f64 { x - trunc(x) diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index e2249bd7f6a11..4cfac9ecc2ab7 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -19,7 +19,6 @@ #![feature(const_deref)] #![feature(const_destruct)] #![feature(const_eval_select)] -#![feature(const_float_round_methods)] #![feature(const_ops)] #![feature(const_ref_cell)] #![feature(const_trait_impl)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 311b2cb932392..323742a75b055 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -329,7 +329,6 @@ #![feature(bstr_internals)] #![feature(char_internals)] #![feature(clone_to_uninit)] -#![feature(const_float_round_methods)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(duration_constants)] diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index e79ec2ae966ff..2bff73add33d6 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -44,7 +44,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn floor(self) -> f32 { core::f32::math::floor(self) @@ -67,7 +67,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn ceil(self) -> f32 { core::f32::math::ceil(self) @@ -96,7 +96,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round(self) -> f32 { core::f32::math::round(self) @@ -123,7 +123,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round_ties_even(self) -> f32 { core::f32::math::round_ties_even(self) @@ -149,7 +149,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trunc(self) -> f32 { core::f32::math::trunc(self) @@ -173,7 +173,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn fract(self) -> f32 { core::f32::math::fract(self) diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 853417825f97a..b71e319f4074f 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -44,7 +44,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn floor(self) -> f64 { core::f64::math::floor(self) @@ -67,7 +67,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn ceil(self) -> f64 { core::f64::math::ceil(self) @@ -96,7 +96,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round(self) -> f64 { core::f64::math::round(self) @@ -123,7 +123,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round_ties_even(self) -> f64 { core::f64::math::round_ties_even(self) @@ -149,7 +149,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trunc(self) -> f64 { core::f64::math::trunc(self) @@ -173,7 +173,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn fract(self) -> f64 { core::f64::math::fract(self) From caf4f111bc371d148eb6b2e01dcadc90b4a8b877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nurzhan=20Sak=C3=A9n?= Date: Mon, 7 Jul 2025 23:23:11 +0400 Subject: [PATCH 16/19] Add `#[rustc_intrinsic_const_stable_indirect]` to float rounding intrinsics --- library/core/src/intrinsics/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index f90e6851d1f5f..106cc725fee2c 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1379,6 +1379,7 @@ pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::floor`](../../std/primitive.f16.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf16(x: f16) -> f16; @@ -1386,6 +1387,7 @@ pub const unsafe fn floorf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::floor`](../../std/primitive.f32.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf32(x: f32) -> f32; @@ -1393,6 +1395,7 @@ pub const unsafe fn floorf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::floor`](../../std/primitive.f64.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf64(x: f64) -> f64; @@ -1400,6 +1403,7 @@ pub const unsafe fn floorf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::floor`](../../std/primitive.f128.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf128(x: f128) -> f128; @@ -1408,6 +1412,7 @@ pub const unsafe fn floorf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf16(x: f16) -> f16; @@ -1415,6 +1420,7 @@ pub const unsafe fn ceilf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf32(x: f32) -> f32; @@ -1422,6 +1428,7 @@ pub const unsafe fn ceilf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf64(x: f64) -> f64; @@ -1429,6 +1436,7 @@ pub const unsafe fn ceilf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf128(x: f128) -> f128; @@ -1437,6 +1445,7 @@ pub const unsafe fn ceilf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf16(x: f16) -> f16; @@ -1444,6 +1453,7 @@ pub const unsafe fn truncf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf32(x: f32) -> f32; @@ -1451,6 +1461,7 @@ pub const unsafe fn truncf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf64(x: f64) -> f64; @@ -1458,6 +1469,7 @@ pub const unsafe fn truncf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf128(x: f128) -> f128; @@ -1467,6 +1479,7 @@ pub const unsafe fn truncf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f16(x: f16) -> f16; @@ -1476,6 +1489,7 @@ pub const fn round_ties_even_f16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f32(x: f32) -> f32; @@ -1485,6 +1499,7 @@ pub const fn round_ties_even_f32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f64(x: f64) -> f64; @@ -1494,6 +1509,7 @@ pub const fn round_ties_even_f64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f128(x: f128) -> f128; @@ -1502,6 +1518,7 @@ pub const fn round_ties_even_f128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::round`](../../std/primitive.f16.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf16(x: f16) -> f16; @@ -1509,6 +1526,7 @@ pub const unsafe fn roundf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::round`](../../std/primitive.f32.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf32(x: f32) -> f32; @@ -1516,6 +1534,7 @@ pub const unsafe fn roundf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::round`](../../std/primitive.f64.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf64(x: f64) -> f64; @@ -1523,6 +1542,7 @@ pub const unsafe fn roundf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::round`](../../std/primitive.f128.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf128(x: f128) -> f128; From 2f14d0a65d7ec8ee35e7f25ddd996ae40615a2a3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Jul 2025 22:29:13 +0200 Subject: [PATCH 17/19] Add code comment explaining better what `Row.name` is for doc aliases --- src/librustdoc/html/static/js/rustdoc.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 9ce24d1c06f60..a958976454781 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -219,6 +219,8 @@ declare namespace rustdoc { crate: string, descShard: SearchDescShard, id: number, + // This is the name of the item. For doc aliases, if you want the name of the aliased + // item, take a look at `Row.original.name`. name: string, normalizedName: string, word: string, From db1449aed549ea8f7f4b1809cf262e70dbf00eeb Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 19 Jul 2025 22:05:25 +0000 Subject: [PATCH 18/19] Initialize mingw for the runner's user --- .github/workflows/ci.yml | 5 ----- src/ci/scripts/install-mingw.sh | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc8ac539a3a09..e92afc14c20da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,11 +182,6 @@ jobs: - name: install MinGW run: src/ci/scripts/install-mingw.sh - # Workaround for spurious ci failures after mingw install - # see https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Spurious.20bors.20CI.20failures/near/528915775 - - name: ensure home dir exists - run: mkdir -p ~ - - name: install ninja run: src/ci/scripts/install-ninja.sh diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index ad852071f2950..ed87628659b41 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -43,4 +43,9 @@ if isWindows && isKnownToBeMingwBuild; then curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" 7z x -y mingw.7z > /dev/null ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")" + + # Initialize mingw for the user. + # This should be done by github but isn't for some reason. + # (see https://github.com/actions/runner-images/issues/12600) + /c/msys64/usr/bin/bash -lc ' ' fi From 56288857d880bf8fc28a7bd49ba8ed99cb8bd318 Mon Sep 17 00:00:00 2001 From: ltdk Date: Thu, 17 Jul 2025 23:22:12 -0400 Subject: [PATCH 19/19] Remove deprecated MaybeUninit slice methods --- library/core/src/mem/maybe_uninit.rs | 114 +-------------------------- 1 file changed, 2 insertions(+), 112 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index fc35e54bb0dcc..34d8370da7ecb 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1005,28 +1005,6 @@ impl MaybeUninit { } } - /// Deprecated version of [`slice::assume_init_ref`]. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[deprecated( - note = "replaced by inherent assume_init_ref method; will eventually be removed", - since = "1.83.0" - )] - pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { - // SAFETY: Same for both methods. - unsafe { slice.assume_init_ref() } - } - - /// Deprecated version of [`slice::assume_init_mut`]. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[deprecated( - note = "replaced by inherent assume_init_mut method; will eventually be removed", - since = "1.83.0" - )] - pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { - // SAFETY: Same for both methods. - unsafe { slice.assume_init_mut() } - } - /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] @@ -1040,94 +1018,6 @@ impl MaybeUninit { pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } - - /// Deprecated version of [`slice::write_copy_of_slice`]. - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - #[deprecated( - note = "replaced by inherent write_copy_of_slice method; will eventually be removed", - since = "1.83.0" - )] - pub fn copy_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Copy, - { - this.write_copy_of_slice(src) - } - - /// Deprecated version of [`slice::write_clone_of_slice`]. - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - #[deprecated( - note = "replaced by inherent write_clone_of_slice method; will eventually be removed", - since = "1.83.0" - )] - pub fn clone_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Clone, - { - this.write_clone_of_slice(src) - } - - /// Deprecated version of [`slice::write_filled`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_filled method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill<'a>(this: &'a mut [MaybeUninit], value: T) -> &'a mut [T] - where - T: Clone, - { - this.write_filled(value) - } - - /// Deprecated version of [`slice::write_with`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_with method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit], mut f: F) -> &'a mut [T] - where - F: FnMut() -> T, - { - this.write_with(|_| f()) - } - - /// Deprecated version of [`slice::write_iter`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_iter method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill_from<'a, I>( - this: &'a mut [MaybeUninit], - it: I, - ) -> (&'a mut [T], &'a mut [MaybeUninit]) - where - I: IntoIterator, - { - this.write_iter(it) - } - - /// Deprecated version of [`slice::as_bytes`]. - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - #[deprecated( - note = "replaced by inherent as_bytes method; will eventually be removed", - since = "1.83.0" - )] - pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { - this.as_bytes() - } - - /// Deprecated version of [`slice::as_bytes_mut`]. - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - #[deprecated( - note = "replaced by inherent as_bytes_mut method; will eventually be removed", - since = "1.83.0" - )] - pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { - this.as_bytes_mut() - } } impl [MaybeUninit] { @@ -1304,7 +1194,7 @@ impl [MaybeUninit] { /// Fills a slice with elements returned by calling a closure for each index. /// /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use - /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can + /// [slice::write_filled]. If you want to use the `Default` trait to generate values, you can /// pass [`|_| Default::default()`][Default::default] as the argument. /// /// # Panics @@ -1463,7 +1353,7 @@ impl [MaybeUninit] { /// use std::mem::MaybeUninit; /// /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; - /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit); + /// let uninit_bytes = uninit.as_bytes_mut(); /// uninit_bytes.write_copy_of_slice(&[0x12, 0x34, 0x56, 0x78]); /// let vals = unsafe { uninit.assume_init_ref() }; /// if cfg!(target_endian = "little") {