diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 33c0f584c8..41ca4789ee 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -498,6 +498,11 @@ class cpp_function : public function { } else { signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name())); } + } else if (c == '!' + && (*(pc + 1) == '!' || *(pc + 1) == '@' || *(pc + 1) == '%' + || *(pc + 1) == '{' || *(pc + 1) == '}')) { + // typing::Literal escapes special characters with ! + signature += *++pc; } else if (c == '@') { // `@^ ... @!` and `@$ ... @!` are used to force arg/return value type (see // typing::Callable/detail::arg_descr/detail::return_descr) diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index fac145bfc5..dade12b75c 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -120,6 +120,36 @@ struct StringLiteral { char name[N]; }; +template +consteval auto sanitize_string_literal() { + constexpr std::string_view v(str.name); + char result[v.size() + std::ranges::count(v, '!') + std::ranges::count(v, '@') + + std::ranges::count(v, '%') + std::ranges::count(v, '{') + + std::ranges::count(v, '}') + 1]; + size_t i = 0; + for (auto c : str.name) { + if (c == '!') { + result[i++] = '!'; + result[i++] = '!'; + } else if (c == '@') { + result[i++] = '!'; + result[i++] = '@'; + } else if (c == '%') { + result[i++] = '!'; + result[i++] = '%'; + } else if (c == '{') { + result[i++] = '!'; + result[i++] = '{'; + } else if (c == '}') { + result[i++] = '!'; + result[i++] = '}'; + } else { + result[i++] = c; + } + } + return StringLiteral(result); +} + template class Literal : public object { PYBIND11_OBJECT_DEFAULT(Literal, object, PyObject_Type) @@ -253,13 +283,14 @@ struct handle_type_name { #if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL) template struct handle_type_name> { - static constexpr auto name = const_name("Literal[") - + pybind11::detail::concat(const_name(Literals.name)...) - + const_name("]"); + static constexpr auto name + = const_name("Literal[") + + pybind11::detail::concat(const_name(sanitize_string_literal().name)...) + + const_name("]"); }; template struct handle_type_name> { - static constexpr auto name = const_name(StrLit.name); + static constexpr auto name = const_name(sanitize_string_literal().name); }; #endif