From ead9f5825184cff3509da36be20bb9ff87e3135d Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 21 Aug 2025 15:48:29 -0500 Subject: [PATCH 1/6] make primitive:pointer work in type-based search. --- src/librustdoc/html/render/search_index.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 41657e290ea21..1ccffef15bb85 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1855,7 +1855,7 @@ fn get_index_type_id( } clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)), - clean::RawPointer(_, ref type_) => get_index_type_id(type_, rgen), + clean::RawPointer{ .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)), // The type parameters are converted to generics in `simplify_fn_type` clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)), clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)), @@ -2113,7 +2113,7 @@ fn simplify_fn_type<'a, 'tcx>( generics: Some(ty_generics), }); } - Type::BorrowedRef { lifetime: _, mutability, ref type_ } => { + Type::BorrowedRef { lifetime: _, mutability, ref type_ } | Type::RawPointer(mutability, ref type_)=> { let mut ty_generics = Vec::new(); if mutability.is_mut() { ty_generics.push(RenderType { From 4b730a2010884c3478bf53d55321a5987edf6fda Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 21 Aug 2025 16:12:07 -0500 Subject: [PATCH 2/6] rustdoc search: accept *mut T syntax for raw pointers --- src/librustdoc/html/static/js/search.js | 75 +++++++++++++++---------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 42b87d562529b..6f90575fe65e4 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -587,6 +587,44 @@ function getNextElem(query, parserState, elems, isInGenerics) { /** @type {rustdoc.ParserQueryElement[]} */ const generics = []; + /** @type {function(string, string): void} */ + const handleRefOrPtr = (chr, name) => { + if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { + throw [ + "Invalid search type: primitive ", + chr, + " and ", + parserState.typeFilter, + " both specified", + ]; + } + parserState.typeFilter = null; + parserState.pos += 1; + let c = parserState.userQuery[parserState.pos]; + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + const generics = []; + if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") { + generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); + parserState.pos += 3; + c = parserState.userQuery[parserState.pos]; + } else if (chr === "*" && parserState.userQuery.slice(pos, pos + 5) === "const") { + // make *const T parse the same as *T + parserState.pos += 5; + c = parserState.userQuery[parserState.pos]; + } + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + if (!isEndCharacter(c) && parserState.pos < parserState.length) { + getFilteredNextElem(query, parserState, generics, isInGenerics); + } + elems.push(makePrimitiveElement(name, { generics })); + } + skipWhitespace(parserState); let start = parserState.pos; let end; @@ -636,36 +674,9 @@ function getNextElem(query, parserState, elems, isInGenerics) { elems.push(makePrimitiveElement(name, { bindingName, generics })); } } else if (parserState.userQuery[parserState.pos] === "&") { - if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { - throw [ - "Invalid search type: primitive ", - "&", - " and ", - parserState.typeFilter, - " both specified", - ]; - } - parserState.typeFilter = null; - parserState.pos += 1; - let c = parserState.userQuery[parserState.pos]; - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - const generics = []; - if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") { - generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); - parserState.pos += 3; - c = parserState.userQuery[parserState.pos]; - } - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - if (!isEndCharacter(c) && parserState.pos < parserState.length) { - getFilteredNextElem(query, parserState, generics, isInGenerics); - } - elems.push(makePrimitiveElement("reference", { generics })); + handleRefOrPtr("&", "reference"); + } else if (parserState.userQuery[parserState.pos] === "*") { + handleRefOrPtr("*", "pointer"); } else { const isStringElem = parserState.userQuery[start] === "\""; // We handle the strings on their own mostly to make code easier to follow. @@ -1185,6 +1196,7 @@ class DocSearch { this.typeNameIdOfUnit = -1; this.typeNameIdOfTupleOrUnit = -1; this.typeNameIdOfReference = -1; + this.typeNameIdOfPointer = -1; this.typeNameIdOfHof = -1; this.utf8decoder = new TextDecoder(); @@ -1224,6 +1236,7 @@ class DocSearch { tupleOrUnit, // reference matches `&` reference, + pointer, // never matches `!` never, ] = await Promise.all([ @@ -1239,6 +1252,7 @@ class DocSearch { nn.search("unit"), nn.search("()"), nn.search("reference"), + nn.search("pointer"), nn.search("never"), ]); /** @@ -1270,6 +1284,7 @@ class DocSearch { this.typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, ""); this.typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, ""); this.typeNameIdOfReference = await first(reference, TY_PRIMITIVE, ""); + this.typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, ""); this.typeNameIdOfHof = await first(hof, TY_PRIMITIVE, ""); this.typeNameIdOfNever = await first(never, TY_PRIMITIVE, ""); } From ae9845fbc9397956cfeb56f532e3b0eee841f315 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 21 Aug 2025 17:14:08 -0500 Subject: [PATCH 3/6] add special formatting for displaying raw pointers in signatures --- src/librustdoc/html/static/js/search.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 6f90575fe65e4..5e65791bb6695 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -606,7 +606,8 @@ function getNextElem(query, parserState, elems, isInGenerics) { c = parserState.userQuery[parserState.pos]; } const generics = []; - if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") { + const pos = parserState.pos; + if (parserState.userQuery.slice(pos, pos + 3) === "mut") { generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); parserState.pos += 3; c = parserState.userQuery[parserState.pos]; @@ -623,7 +624,7 @@ function getNextElem(query, parserState, elems, isInGenerics) { getFilteredNextElem(query, parserState, generics, isInGenerics); } elems.push(makePrimitiveElement(name, { generics })); - } + }; skipWhitespace(parserState); let start = parserState.pos; @@ -2324,6 +2325,25 @@ class DocSearch { }, result), ); return true; + } else if (fnType.id === this.typeNameIdOfPointer) { + pushText({ name: "*", highlighted: fnType.highlighted }, result); + if (fnType.generics.length < 2) { + pushText({ name: "const ", highlighted: fnType.highlighted }, result); + } + let prevHighlighted = false; + await onEachBtwnAsync( + fnType.generics, + async value => { + prevHighlighted = !!value.highlighted; + await writeFn(value, result); + }, + // @ts-expect-error + value => pushText({ + name: " ", + highlighted: prevHighlighted && value.highlighted, + }, result), + ); + return true; } else if ( fnType.id === this.typeNameIdOfFn || fnType.id === this.typeNameIdOfFnMut || From eeaad503df184e75b870cfb4492388711d7a6947 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 21 Aug 2025 17:18:20 -0500 Subject: [PATCH 4/6] unbox raw pointers in type-based search --- src/librustdoc/html/render/search_index.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 1ccffef15bb85..dddc087d124df 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1494,7 +1494,9 @@ pub(crate) fn build_index( let search_unbox = match id { RenderTypeId::Mut => false, RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox), - RenderTypeId::Primitive(PrimitiveType::Reference | PrimitiveType::Tuple) => true, + RenderTypeId::Primitive( + PrimitiveType::Reference | PrimitiveType::RawPointer | PrimitiveType::Tuple, + ) => true, RenderTypeId::Primitive(..) => false, RenderTypeId::AssociatedType(..) => false, // this bool is only used by `insert_into_map`, so it doesn't matter what we set here @@ -1855,7 +1857,7 @@ fn get_index_type_id( } clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)), - clean::RawPointer{ .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)), + clean::RawPointer { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)), // The type parameters are converted to generics in `simplify_fn_type` clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)), clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)), @@ -2113,7 +2115,8 @@ fn simplify_fn_type<'a, 'tcx>( generics: Some(ty_generics), }); } - Type::BorrowedRef { lifetime: _, mutability, ref type_ } | Type::RawPointer(mutability, ref type_)=> { + Type::BorrowedRef { lifetime: _, mutability, ref type_ } + | Type::RawPointer(mutability, ref type_) => { let mut ty_generics = Vec::new(); if mutability.is_mut() { ty_generics.push(RenderType { From 3501e4f3f2a0501d353fb97ca823443203095682 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 21 Aug 2025 17:43:04 -0500 Subject: [PATCH 5/6] rustdoc: add tests for raw pointers in type-based search --- tests/rustdoc-js/pointer.js | 240 ++++++++++++++++++++++++++++++++++++ tests/rustdoc-js/pointer.rs | 40 ++++++ 2 files changed, 280 insertions(+) create mode 100644 tests/rustdoc-js/pointer.js create mode 100644 tests/rustdoc-js/pointer.rs diff --git a/tests/rustdoc-js/pointer.js b/tests/rustdoc-js/pointer.js new file mode 100644 index 0000000000000..b2b556858fdbb --- /dev/null +++ b/tests/rustdoc-js/pointer.js @@ -0,0 +1,240 @@ +// exact-check + +const EXPECTED = [ + // pinkie with explicit names + { + 'query': 'usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': 'pointer, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + { + 'query': 'pointer, usize -> ()', + 'others': [], + }, + // thumb with explicit names + { + 'query': 'thumb, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': 'pointer, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + { + 'query': 'pointer, thumb -> ()', + 'others': [], + }, + // index with explicit names + { + 'query': 'index, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': 'pointer, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + { + 'query': 'pointer, index -> ()', + 'others': [], + }, + // ring with explicit names + { + 'query': 'ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + // can't leave out the `mut`, because can't reorder like that + 'others': [], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [], + }, + // middle with explicit names + { + 'query': 'middle, middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer, pointer -> ()', + // can't leave out the mut + 'others': [], + }, + { + 'query': 'pointer, pointer -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [], + }, + { + 'query': 'pointer>, pointer> -> ()', + 'others': [], + }, + // pinkie with shorthand + { + 'query': '*const usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + // you can omit the `const`, if you want. + { + 'query': '*usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': '*const usize, *const usize -> ()', + 'others': [], + }, + { + 'query': '*mut usize, usize -> ()', + 'others': [], + }, + // thumb with shorthand + { + 'query': '*const thumb, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': '*const thumb, *const thumb -> ()', + 'others': [], + }, + { + 'query': '*mut thumb, thumb -> ()', + 'others': [], + }, + // index with explicit names + { + 'query': '*const index, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': '*const index, *const index -> ()', + 'others': [], + }, + { + 'query': '*mut index, index -> ()', + 'others': [], + }, + // ring with shorthand + { + 'query': '*const ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*const ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*mut ring, *const ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*mut ring, *mut ring -> ()', + 'others': [], + }, + // middle with shorthand + { + 'query': '*const middle, *const middle -> ()', + // can't leave out the mut + 'others': [], + }, + { + 'query': '*mut middle, *mut middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*const *mut middle, *mut *const middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*mut *const middle, *const *mut middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*const *mut middle, *const *mut middle -> ()', + 'others': [], + }, + { + 'query': '*mut *const middle, *mut *const middle -> ()', + 'others': [], + }, +]; diff --git a/tests/rustdoc-js/pointer.rs b/tests/rustdoc-js/pointer.rs new file mode 100644 index 0000000000000..8375a17430360 --- /dev/null +++ b/tests/rustdoc-js/pointer.rs @@ -0,0 +1,40 @@ +#![feature(extern_types)] + +pub fn pinky(input: *const usize, manage: usize) { + unimplemented!() +} + +pub struct Thumb; + +impl Thumb { + pub fn up(this: *const Self, finger: Thumb) { + unimplemented!() + } +} + +pub enum Index {} + +impl Index { + pub fn point(self, data: *const Index) { + unimplemented!() + } +} + +pub union Ring { + magic: u32, + marriage: f32, +} + +impl Ring { + pub fn wear(this: *mut Self, extra: *const Ring) { + unimplemented!() + } +} + +extern "C" { + pub type Middle; +} + +pub fn show(left: *const *mut Middle, right: *mut *const Middle) { + unimplemented!() +} From 401f40f1c19bb7055918b6409a73adc55edde39f Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 21 Aug 2025 20:50:33 -0500 Subject: [PATCH 6/6] tests/rustdoc-js-std/parser-errors.js: remove syntax that is now valid --- tests/rustdoc-js-std/parser-errors.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index 49150cbd570ac..6e11dda8532fa 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -15,14 +15,6 @@ const PARSED = [ returned: [], error: "Found generics without a path", }, - { - query: '-> *', - elems: [], - foundElems: 0, - userQuery: "-> *", - returned: [], - error: "Unexpected `*` after ` ` (not a valid identifier)", - }, { query: 'a<"P">', elems: [],