Adding GNU C++ demangler#1834
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis pull request introduces comprehensive GNU C++ symbol demangling support using the PEGTL parsing library. Changes include a new demangler implementation with grammar rules and parse-tree walker, integration into the build system across multiple platforms, emulator settings for controlling display behavior, and GUI updates to conditionally show demangled symbol names in assembly and callstack views. Changes
Sequence DiagramssequenceDiagram
participant User
participant GUI as Assembly Widget
participant Emulator as Emulator Settings
participant Demangler as GNUDemangler
participant PEGTL as PEGTL Parser
participant TreeWalk as TreeWalker
User->>GUI: View assembly with symbol
GUI->>Emulator: Check DemangledSymbols setting
alt Demangling enabled
GUI->>Demangler: demangle(mangled_symbol)
Demangler->>Demangler: Validate "_Z" prefix
Demangler->>PEGTL: Parse with DemanglerSelector
PEGTL->>TreeWalk: Create parse tree
TreeWalk->>TreeWalk: Walk tree recursively
TreeWalk->>TreeWalk: Resolve substitutions, templates, operators
TreeWalk->>TreeWalk: Build demangled string
TreeWalk-->>Demangler: Return demangled name
Demangler-->>GUI: Return demangled string
else Demangling disabled
Demangler-->>GUI: Return original symbol
end
GUI->>GUI: Render symbol in assembly view
GUI-->>User: Display demangled/raw symbol
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/support/gnu-c++-demangler.cc (1)
366-371: Enhance error handling in thedemanglefunction.Currently, if parsing fails, the function returns the original mangled name without any indication of the error. Consider logging the error or providing more detailed error information to assist with debugging.
src/support/gnu-c++-demangler.h (1)
36-38: Add documentation for public functions.The functions
internalCheck(),trace(std::string_view mangled), anddemangle(std::string_view mangled)are part of the public interface. Adding documentation comments will improve readability and help other developers understand the purpose and usage of these functions.LICENSES.md (1)
56-56: Fix markdown list indentation.The list item indentation is inconsistent with the rest of the file. Consider fixing the indentation to match other entries.
- - [PEGTL](https://github.com/taocpp/PEGTL) + - [PEGTL](https://github.com/taocpp/PEGTL)🧰 Tools
🪛 Markdownlint (0.37.0)
56-56: Expected: 0; Actual: 1
Unordered list indentation(MD007, ul-indent)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.gitmodules(1 hunks)LICENSES.md(1 hunks)Makefile(1 hunks)src/support/gnu-c++-demangler.cc(1 hunks)src/support/gnu-c++-demangler.h(1 hunks)third_party/PEGTL(1 hunks)vsprojects/common.props(1 hunks)vsprojects/pcsx-redux.sln(2 hunks)vsprojects/support/support.vcxproj(2 hunks)vsprojects/support/support.vcxproj.filters(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- third_party/PEGTL
👮 Files not reviewed due to content moderation or server errors (1)
- vsprojects/support/support.vcxproj.filters
🧰 Additional context used
🪛 Markdownlint (0.37.0)
LICENSES.md
56-56: Expected: 0; Actual: 1
Unordered list indentation
(MD007, ul-indent)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (8)
vsprojects/common.props (1)
11-11: Verify the correctness of the added include directory path.The path
$(SolutionDir)..\third_party\PEGTL\include;has been added toAdditionalIncludeDirectories. Please verify that this path is correct and accessible during the build process to ensure that the PEGTL headers are included properly.Makefile (1)
39-39: LGTM!The PEGTL include path is correctly added and follows the existing pattern in the Makefile.
.gitmodules (1)
97-99: LGTM! Clean addition of PEGTL dependencyThe addition of PEGTL as a submodule follows project conventions and uses the official repository.
vsprojects/support/support.vcxproj (2)
163-163: LGTM! Header file addition follows conventionsThe gnu-c++-demangler.h header is properly integrated into the project structure.
213-215: Verify if /bigobj is needed for other configurationsThe /bigobj compiler option is added only for Debug|x64. Consider if this option is also needed for other configurations to handle large object files generated by template-heavy PEGTL code.
✅ Verification successful
Keep /bigobj option specific to Debug|x64 configuration
The current configuration appears correct. The gnu-c++-demangler.cc file (20KB) is the largest in the support directory and likely generates large object files specifically in Debug builds due to template expansion and debug symbols. Release builds typically have better template instantiation optimization, explaining why the option isn't needed there.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check if other configurations might need /bigobj by looking for similar patterns rg -l "bigobj" vsprojects/Length of output: 61
Script:
#!/bin/bash # Get more context around bigobj usage rg -C 5 "bigobj" vsprojects/support/support.vcxproj # Check for the specific file in other configurations rg -A 5 "gnu-c\+\+-demangler\.cc" vsprojects/support/support.vcxproj # Look for other potential template-heavy files fd . src/support -e cc -x ls -l {} \;Length of output: 2767
vsprojects/pcsx-redux.sln (3)
110-114: LGTM! Well-structured PEGTL integrationThe PEGTL root folder is properly added under third_party with the main header.
780-785: LGTM! Proper nesting of PEGTL componentsThe folder hierarchy correctly organizes PEGTL components (core, contrib, internal) maintaining clean project structure.
789-789: Update SolutionGuid to maintain solution identityThe solution GUID has been updated, which is expected when adding new projects.
src/support/gnu-c++-demangler.cc
Outdated
| size *= 10; | ||
| size += in.peek_char() - '0'; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Check for potential integer overflow in size calculation.
The size variable is calculated by accumulating digit characters in lines 103-104. If the mangled name contains a very large number, there is a risk of integer overflow. Consider adding a check to prevent overflow or using a larger integer type like std::size_t.
src/support/gnu-c++-demangler.cc
Outdated
| while (in.size() > 0 && std::isdigit(in.peek_char())) { | ||
| size *= 10; | ||
| size += in.peek_char() - '0'; | ||
| in.bump(1); |
There was a problem hiding this comment.
Cast char to unsigned char when using std::isdigit.
In the source_name::match function, std::isdigit(in.peek_char()) is called on line 102. Since std::isdigit expects an int that is representable as an unsigned char or EOF, passing a char directly can lead to undefined behavior if char is signed and contains a negative value. To ensure correct behavior, cast the character to unsigned char before passing it to std::isdigit.
Apply this diff to fix the issue:
- while (in.size() > 0 && std::isdigit(in.peek_char())) {
+ while (in.size() > 0 && std::isdigit(static_cast<unsigned char>(in.peek_char()))) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| while (in.size() > 0 && std::isdigit(in.peek_char())) { | |
| size *= 10; | |
| size += in.peek_char() - '0'; | |
| in.bump(1); | |
| while (in.size() > 0 && std::isdigit(static_cast<unsigned char>(in.peek_char()))) { | |
| size *= 10; | |
| size += in.peek_char() - '0'; | |
| in.bump(1); |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/support/gnu-c++-demangler.cc (1)
50-55: Improve debugbreak implementation for non-Windows platforms.The non-Windows implementation of
debugbreak()is empty. Consider:
- Using platform-specific debug break mechanisms (e.g.,
raise(SIGTRAP)on Unix).- Adding a compile-time warning when debug breaks are unavailable.
#ifdef _WIN32 void debugbreak() { if (IsDebuggerPresent()) __debugbreak(); } #else void debugbreak() { #if defined(__unix__) || defined(__unix) || defined(__APPLE__) raise(SIGTRAP); #else #warning "Debug break not implemented for this platform" #endif } #endif
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/support/gnu-c++-demangler.cc(1 hunks)src/support/gnu-c++-demangler.h(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: macos-intel-build-and-test
- GitHub Check: macos-arm-build-and-test
- GitHub Check: build
- GitHub Check: toolchain
- GitHub Check: asan
- GitHub Check: aur-build
- GitHub Check: macos-build-and-test-toolchain
- GitHub Check: cross-arm64
- GitHub Check: coverage
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (1)
src/support/gnu-c++-demangler.cc (1)
129-148:⚠️ Potential issueFix potential issues in source_name implementation.
The
source_nameimplementation has several issues:
- Integer overflow possible in size calculation
- Unsafe usage of
std::isdigit- No bounds checking on string_view access
struct source_name { using rule_t = source_name; using subs_t = pegtl::nothing<void>; template <pegtl::apply_mode A, pegtl::rewind_mode M, template <typename...> class Action, template <typename...> class Control, typename ParseInput, typename... States> [[nodiscard]] static bool match(ParseInput& in, States&&... st) { auto marker = in.template mark<M>(); - unsigned size = 0; + std::size_t size = 0; + const std::size_t maxSize = std::numeric_limits<std::size_t>::max(); while (in.size() > 0 && std::isdigit(static_cast<unsigned char>(in.peek_char()))) { + if (size > maxSize / 10) return marker(false); // Prevent overflow size *= 10; - size += in.peek_char() - '0'; + std::size_t digit = in.peek_char() - '0'; + if (size > maxSize - digit) return marker(false); // Prevent overflow + size += digit; in.bump(1); } if (size == 0) return marker(false); if (in.size() < size) return marker(false); in.bump(size); return marker(true); } };Likely invalid or redundant comment.
| bool internalCheck(); | ||
| bool trace(std::string_view mangled); | ||
| bool printDot(std::string_view mangled); | ||
| std::string demangle(std::string_view mangled); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add documentation for the public API.
The public functions lack documentation. Please add Doxygen-style comments explaining:
- Purpose of each function
- Parameters and their meaning
- Return value semantics
- Example usage if applicable
Example documentation format:
/**
* Performs internal validation of the demangler grammar.
* @return true if the grammar is valid, false otherwise.
*/
bool internalCheck();
/**
* Traces the demangling process for a mangled name.
* @param mangled The mangled name to trace
* @return true if tracing succeeded, false otherwise
*/
bool trace(std::string_view mangled);
src/support/gnu-c++-demangler.h
Outdated
|
|
||
| MIT License | ||
|
|
||
| Copyright (c) 2025 PCSX-Redux authors |
There was a problem hiding this comment.
Update the copyright year.
The copyright year is set to 2025, which is in the future. Please update it to the current year (2024).
-Copyright (c) 2025 PCSX-Redux authors
+Copyright (c) 2024 PCSX-Redux authors📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Copyright (c) 2025 PCSX-Redux authors | |
| Copyright (c) 2024 PCSX-Redux authors |
src/support/gnu-c++-demangler.cc
Outdated
| struct DemanglerState { | ||
| std::string tostring() { return ""; } | ||
| std::vector<std::string> bag; | ||
| std::string_view lastName; | ||
| const std::type_info* lastAction; | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve DemanglerState implementation.
The DemanglerState class needs improvements:
tostring()returns an empty string but should format the state.- Member variables lack documentation.
- Consider making
tostring()const-qualified.
struct DemanglerState {
/// Returns a string representation of the current state
std::string tostring() const {
std::string result;
if (!bag.empty()) {
result = "Names: ";
for (const auto& name : bag) {
result += name + ", ";
}
result.resize(result.size() - 2); // Remove trailing ", "
}
return result;
}
std::vector<std::string> bag; ///< Collected names during parsing
std::string_view lastName; ///< Most recently parsed name
const std::type_info* lastAction; ///< Type info of last executed action
};
src/support/gnu-c++-demangler.cc
Outdated
| template <typename Rule> | ||
| struct DemanglerAction : pegtl::nothing<Rule> {}; | ||
|
|
||
| template <> | ||
| struct DemanglerAction<mangled_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("mangled_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<encoding> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("encoding"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<function> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("function"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_decl> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_decl"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unscoped_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unscoped_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<std_unqualified_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("std_unqualified_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unscoped_template_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unscoped_template_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<nested_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("nested_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<prefix> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("prefix"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_prefix_with_args> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_prefix_with_args"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_prefix> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_prefix"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unqualified_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unqualified_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<source_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| unsigned size = 0; | ||
| auto lengthPrefixedString = in.string_view(); | ||
| unsigned prefixLength = 0; | ||
| while (std::isdigit(lengthPrefixedString[prefixLength])) { | ||
| size *= 10; | ||
| size += lengthPrefixedString[prefixLength++]; | ||
| } | ||
| state.lastName = state.bag.emplace_back(lengthPrefixedString.substr(prefixLength)); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<new_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("new_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<new_array_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("new_array_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<delete_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("delete_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<delete_array_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("delete_array_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unary_plus_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unary_plus_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unary_minus_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unary_minus_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unary_address_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unary_address_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unary_deference_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unary_deference_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bitwise_not_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bitwise_not_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<plus_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("plus_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<minus_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("minus_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<multiply_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("multiply_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<divide_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("divide_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<remainder_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("remainder_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bitwise_and_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bitwise_and_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bitwise_or_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bitwise_or_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bitwise_xor_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bitwise_xor_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<plus_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("plus_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<minus_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("minus_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<multiply_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("multiply_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<divide_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("divide_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<remainder_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("remainder_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bitwise_and_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bitwise_and_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bitwise_or_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bitwise_or_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bitwise_xor_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bitwise_xor_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<left_shift_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("left_shift_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<right_shift_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("right_shift_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<left_shift_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("left_shift_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<right_shift_assign_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("right_shift_assign_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<equal_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("equal_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<not_equal_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("not_equal_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<less_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("less_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<greater_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("greater_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<less_equal_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("less_equal_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<greater_equal_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("greater_equal_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<logical_not_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("logical_not_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<logical_and_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("logical_and_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<logical_or_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("logical_or_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<increment_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("increment_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<decrement_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("decrement_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<comma_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("comma_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<arrow_star_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("arrow_star_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<arrow_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("arrow_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<call_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("call_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<index_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("index_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<question_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("question_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<sizeof_type_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("sizeof_type_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<sizeof_expr_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("sizeof_expr_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<alignof_type_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("alignof_type_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<alignof_expr_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("alignof_expr_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<cast_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("cast_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<vendor_extended_operator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("vendor_extended_operator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<operator_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("operator_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<positive_number> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("positive_number"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<number> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("number"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<nv_offset> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("nv_offset"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<v_offset> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("v_offset"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<call_offset> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("call_offset"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<virtual_table> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("virtual_table"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<vtt_structure> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("vtt_structure"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<typeinfo_structure> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("typeinfo_structure"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<typeinfo_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("typeinfo_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<guard_variable> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("guard_variable"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<virtual_thunk> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("virtual_thunk"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<virtual_covariant_thunk> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("virtual_covariant_thunk"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<special_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("special_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<ctor_dtor_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("ctor_dtor_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<CV_qualified_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("CV_qualified_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<pointer_to_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("pointer_to_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<reference_to_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("reference_to_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<rvalue_reference_to_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("rvalue_reference_to_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<complex_pair_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("complex_pair_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<imaginary_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("imaginary_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<vendor_extended_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("vendor_extended_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<pack_expansion_of_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("pack_expansion_of_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<decltype_of_id_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("decltype_of_id_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<decltype_of_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("decltype_of_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<CV_qualifiers> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("CV_qualifiers"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<void_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("void_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<wchar_t_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("wchar_t_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bool_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bool_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<char_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("char_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<signed_char_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("signed_char_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unsigned_char_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unsigned_char_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<short_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("short_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unsigned_short_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unsigned_short_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<int_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("int_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unsigned_int_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unsigned_int_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<long_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("long_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unsigned_long_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unsigned_long_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<long_long_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("long_long_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unsigned_long_long> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unsigned_long_long"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<int128_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("int128_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unsigned_int128_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unsigned_int128_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<float_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("float_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<double_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("double_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<long_double_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("long_double_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<float128_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("float128_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<ellipsis> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("ellipsis"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<ieee754_64_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("ieee754_64_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<ieee754_128_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("ieee754_128_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<ieee754_32_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("ieee754_32_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<ieee754_16_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("ieee754_16_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<char32_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("char32_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<char16_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("char16_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<vendor_extended_builtin_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("vendor_extended_builtin_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<builtin_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("builtin_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<function_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("function_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<bare_function_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("bare_function_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<array_type_numerical> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("array_type_numerical"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<array_type_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("array_type_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<array_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("array_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<pointer_to_member_type> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("pointer_to_member_type"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_param> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_param"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_template_param> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_template_param"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<function_param> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("function_param"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_args> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_args"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_arg_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_arg_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_arg_pack> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_arg_pack"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_pack_expansion> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_pack_expansion"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<template_arg> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("template_arg"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unary_operator_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unary_operator_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<binary_operator_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("binary_operator_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<trinary_operator_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("trinary_operator_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<call_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("call_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<conversion_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("conversion_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<conversion_multiple_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("conversion_multiple_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<sizeof_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("sizeof_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<alignof_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("alignof_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<dependent_name_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("dependent_name_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<dependent_template_id_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("dependent_template_id_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<dot_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("dot_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<dot_template_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("dot_template_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<arrow_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("arrow_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<arrow_template_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("arrow_template_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<dependent_operator_function_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("dependent_operator_function_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<dependent_operator_function_template_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("dependent_operator_function_template_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<dependent_operator_template_id_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("dependent_operator_template_id_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<sizeof_param_pack_expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("sizeof_param_pack_expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<expression> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("expression"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<hexdigit> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("hexdigit"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<float_value> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("float_value"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<expr_primary_integer> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("expr_primary_integer"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<expr_primary_floating> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("expr_primary_floating"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<expr_primary_external_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("expr_primary_external_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<expr_primary> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("expr_primary"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<discriminator_single_digit> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("discriminator_single_digit"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<discriminator_multiple_digits> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("discriminator_multiple_digits"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<discriminator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("discriminator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<local_name_simple> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("local_name_simple"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unnamed_type_name_simple> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unnamed_type_name_simple"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<unnamed_type_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("unnamed_type_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<lambda_sig> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("lambda_sig"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<closure_type_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("closure_type_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<local_name_lambda> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("local_name_lambda"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<local_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("local_name"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<data_member_prefix> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("data_member_prefix"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<seq_id> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("seq_id"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_simple> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_simple"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_std> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_std"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_std_allocator> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_std_allocator"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_std_basic_string> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_std_basic_string"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_std_basic_string_full> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_std_basic_string_full"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_std_basic_istream> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_std_basic_istream"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_std_basic_ostream> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_std_basic_ostream"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution_std_basic_iostream> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution_std_basic_iostream"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<substitution> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("substitution"); | ||
| } | ||
| }; | ||
| template <> | ||
| struct DemanglerAction<std_name> { | ||
| template <typename ActionInput> | ||
| static void apply(const ActionInput& in, DemanglerState& state) { | ||
| debugbreak(); | ||
| throw Unimplemented("std_name"); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve error handling in DemanglerAction implementations.
The current implementation has several issues:
- All actions throw exceptions, making error recovery impossible
- No progress tracking or partial results
- Debug breaks in every action make debugging cumbersome
Consider implementing a more robust error handling strategy:
- Use a Result type instead of exceptions:
template <typename Rule>
struct DemanglerAction : pegtl::nothing<Rule> {};
// Example improved implementation
template <>
struct DemanglerAction<mangled_name> {
template <typename ActionInput>
static void apply(const ActionInput& in, DemanglerState& state) {
if (state.errorOccurred) return; // Skip if already in error state
try {
// Implementation here
} catch (const std::exception& e) {
state.errorOccurred = true;
state.errorMessage = e.what();
state.errorLocation = in.position();
}
}
};- Add progress tracking:
struct DemanglerState {
// ... existing members ...
/// Tracks parsing progress
struct Progress {
std::size_t totalRules = 0;
std::size_t completedRules = 0;
std::string currentRule;
} progress;
/// Error state
bool errorOccurred = false;
std::string errorMessage;
pegtl::position errorLocation;
};| std::string PCSX::GNUDemangler::demangle(std::string_view mangled) { | ||
| try { | ||
| DemanglerState state; | ||
| pegtl::string_input in(mangled, "mangled"); | ||
| auto result = pegtl::parse<mangled_name, DemanglerAction>(in, state); | ||
| if (result) state.tostring(); | ||
| } catch (Unimplemented unimplemented) { | ||
| std::cout << unimplemented.name; | ||
| } catch (...) { | ||
| } | ||
| return std::string(mangled); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve error handling in demangle function.
The current implementation has several issues:
- Silently catches all exceptions
- Only prints unimplemented rule names
- Always returns the original mangled name on failure
Consider implementing proper error reporting:
struct DemangleError {
enum class Type {
Unimplemented,
InvalidInput,
ParseError,
Internal
};
Type type;
std::string message;
std::optional<std::string> ruleName;
};
std::variant<std::string, DemangleError> demangle(std::string_view mangled) {
try {
DemanglerState state;
pegtl::string_input in(mangled, "mangled");
if (!pegtl::parse<mangled_name, DemanglerAction>(in, state)) {
return DemangleError{
DemangleError::Type::ParseError,
"Failed to parse mangled name",
std::nullopt
};
}
return state.tostring();
} catch (const Unimplemented& e) {
return DemangleError{
DemangleError::Type::Unimplemented,
"Unimplemented demangling rule",
std::string(e.name)
};
} catch (const std::exception& e) {
return DemangleError{
DemangleError::Type::Internal,
e.what(),
std::nullopt
};
}
}There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/support/gnu-c++-demangler.cc (2)
5-5: Update the copyright year.The copyright year is set to 2025, which is in the future. Consider updating it to the current year.
-Copyright (c) 2025 PCSX-Redux authors +Copyright (c) 2024 PCSX-Redux authors
50-55: Enhance debug break for non-Windows platforms.The non-Windows version of
debugbreak()is empty. Consider using platform-specific debug break mechanisms for better debugging support.#else -void debugbreak() {} +void debugbreak() { +#if defined(__APPLE__) + __builtin_debugtrap(); +#elif defined(__unix__) + raise(SIGTRAP); +#else + // Fall back to empty implementation +#endif +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/support/gnu-c++-demangler.cc(1 hunks)src/support/gnu-c++-demangler.h(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/support/gnu-c++-demangler.h
⏰ Context from checks skipped due to timeout of 90000ms (9)
- GitHub Check: macos-intel-build-and-test
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: build
- GitHub Check: asan
- GitHub Check: macos-build-and-test-toolchain
- GitHub Check: toolchain
- GitHub Check: coverage
- GitHub Check: aur-build
- GitHub Check: cross-arm64
🔇 Additional comments (5)
src/support/gnu-c++-demangler.cc (5)
58-63: Improve DemanglerState implementation.The current implementation has several issues:
tostring()returns an empty string but is used indemangle()- Member variables lack documentation
- Consider making
tostring()const-qualified
138-140: Check for potential integer overflow insizecalculation.The
sizevariable is calculated by accumulating digit characters. If the mangled name contains a very large number, there is a risk of integer overflow.
138-141: Castchartounsigned charwhen usingstd::isdigit.Using
std::isdigitwithcharcan lead to undefined behavior ifcharis signed and contains a negative value.
382-1870: Improve error handling in DemanglerAction implementations.The current implementation has several issues:
- All actions throw exceptions, making error recovery impossible
- No progress tracking or partial results
- Debug breaks in every action make debugging cumbersome
1894-1905: Improve error handling in demangle function.The current implementation has several issues:
- Silently catches all exceptions
- Only prints unimplemented rule names
- Always returns the original mangled name on failure
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (5)
src/support/gnu-c++-demangler.cc (5)
61-66: 🛠️ Refactor suggestionImprove DemanglerState implementation.
The
DemanglerStateclass needs improvements:
tostring()returns an empty string but should format the state.- Member variables lack documentation.
- Consider making
tostring()const-qualified.Apply this diff to improve the implementation:
struct DemanglerState { - std::string tostring() { return ""; } - std::vector<std::string> bag; - std::string_view lastName; - const std::type_info* lastAction; + /// Returns a string representation of the current state + std::string tostring() const { + std::string result; + if (!bag.empty()) { + result = "Names: "; + for (const auto& name : bag) { + result += name + ", "; + } + result.resize(result.size() - 2); // Remove trailing ", " + } + return result; + } + + std::vector<std::string> bag; ///< Collected names during parsing + std::string_view lastName; ///< Most recently parsed name + const std::type_info* lastAction; ///< Type info of last executed action };
141-143:⚠️ Potential issueCheck for potential integer overflow in
sizecalculation.The
sizevariable is calculated by accumulating digit characters. If the mangled name contains a very large number, there is a risk of integer overflow.Apply this diff to prevent overflow:
-unsigned size = 0; +std::size_t size = 0; while (in.size() > 0 && std::isdigit(in.peek_char())) { + const auto digit = in.peek_char() - '0'; + if (size > (std::numeric_limits<std::size_t>::max() - digit) / 10) { + return marker(false); // Would overflow + } size *= 10; - size += in.peek_char() - '0'; + size += digit;
141-141:⚠️ Potential issueCast
chartounsigned charwhen usingstd::isdigit.
std::isdigitexpects anintthat is representable as anunsigned charor EOF. Passing achardirectly can lead to undefined behavior ifcharis signed and contains a negative value.Apply this diff to fix the issue:
-while (in.size() > 0 && std::isdigit(in.peek_char())) { +while (in.size() > 0 && std::isdigit(static_cast<unsigned char>(in.peek_char()))) {
385-1873: 🛠️ Refactor suggestionImprove error handling in DemanglerAction implementations.
The current implementation has several issues:
- All actions throw exceptions, making error recovery impossible
- No progress tracking or partial results
- Debug breaks in every action make debugging cumbersome
Consider implementing a more robust error handling strategy as shown in the past review comments.
1897-1908: 🛠️ Refactor suggestionImprove error handling in demangle function.
The current implementation has several issues:
- Silently catches all exceptions
- Only prints unimplemented rule names
- Always returns the original mangled name on failure
Consider implementing proper error reporting as shown in the past review comments.
🧹 Nitpick comments (4)
tests/support/gnu-c++-demangler.cc (2)
1-2: Update the copyright year.The copyright year is set to 2025, which is in the future. Consider updating it to the current year.
- Copyright (C) 2025 PCSX-Redux authors * + Copyright (C) 2024 PCSX-Redux authors *
23-72: Consider enhancing test coverage and documentation.The test suite is comprehensive and well-structured. Consider these improvements:
- Add comments explaining the mangling patterns for complex cases (e.g., lines 55-57 with template arithmetic).
- Add negative test cases to verify proper error handling for invalid mangled names.
Would you like me to help generate additional test cases for invalid inputs and add explanatory comments for the complex test cases?
vsprojects/support/support.vcxproj (1)
213-216: Consider documenting the need for /bigobj.The
/bigobjcompiler option is correctly added for the demangler, which suggests it generates many symbols. Consider:
- Adding a comment explaining why this option is needed
- Documenting this requirement in the project's build documentation
Would you like me to help document this compiler requirement in the project's README or build documentation?
src/support/gnu-c++-demangler.cc (1)
5-5: Update the copyright year.The copyright year is set to 2025, which is in the future. Consider updating it to the current year.
-Copyright (c) 2025 PCSX-Redux authors +Copyright (c) 2024 PCSX-Redux authors
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
compile_flags.txt(1 hunks)src/support/gnu-c++-demangler.cc(1 hunks)tests/support/gnu-c++-demangler.cc(1 hunks)vsprojects/support/support.vcxproj(2 hunks)vsprojects/tests/support/testsupport.vcxproj(1 hunks)
🧰 Additional context used
🪛 LanguageTool
compile_flags.txt
[duplication] ~4-~4: Possibile errore di battitura: parola ripetuta
Context: -std=c++2b -fexceptions -I. -Isrc -Ithird_party -Ithird_party/ELFIO -Ithird_party/fmt/include/ -Ithir...
(ITALIAN_WORD_REPEAT_RULE)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: macos-intel-build-and-test
- GitHub Check: macos-arm-build-and-test
- GitHub Check: cross-arm64
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: asan
- GitHub Check: coverage
- GitHub Check: aur-build
- GitHub Check: toolchain
- GitHub Check: build
- GitHub Check: macos-build-and-test-toolchain
🔇 Additional comments (4)
tests/support/gnu-c++-demangler.cc (1)
20-21: LGTM!The includes are minimal and appropriate for the test file.
vsprojects/tests/support/testsupport.vcxproj (1)
83-83: LGTM!The GNU C++ demangler test file is correctly added to the project.
compile_flags.txt (1)
1-1: Verify compiler compatibility with C++2b.The upgrade to C++2b and addition of PEGTL include path are appropriate. However, ensure that:
- All development environments support C++2b features
- PEGTL library is compatible with C++2b
Run this script to check compiler versions across the build environment:
Also applies to: 19-19
✅ Verification successful
C++2b compatibility verified.
The codebase already makes extensive use of modern C++ features including concepts, coroutines, consteval, and ranges. Since C++2b (C++23) is a superset of C++20, and the project's CI shows successful builds across platforms, the upgrade to C++2b is appropriate and compatible with the development environment.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check compiler versions and C++2b support # Check compiler version c++ --version # Verify C++2b support echo '#include <version>' > test.cpp echo 'int main() { return 0; }' >> test.cpp c++ -std=c++2b -c test.cpp 2>&1 || echo "C++2b not supported"Length of output: 344
Script:
#!/bin/bash # Search for CI configs, build files, and setup documentation echo "=== CI Configurations ===" fd -e yml -e yaml . .github/workflows --exec cat {} echo -e "\n=== Build System Files ===" fd CMakeLists.txt -x cat {} echo -e "\n=== Setup Documentation ===" fd -e md . -d 1 --exec cat {}Length of output: 73528
Script:
#!/bin/bash # Search for compiler version requirements and C++20 feature usage echo "=== Searching for compiler requirements ===" rg -i "cmake_minimum|c\+\+|compiler|std=" --type cmake echo -e "\n=== Searching for C++20 feature usage ===" rg "concept|requires|constinit|consteval|co_await|co_yield|co_return|ranges::|views::|<span>|<concepts>|<ranges>|<coroutine>" --type cppLength of output: 37200
src/support/gnu-c++-demangler.cc (1)
52-58: LGTM!The debug utilities are properly implemented with platform-specific handling.
The previous state had the grammar complete with action handler stubs and debugbreak() calls as tracing scaffolding while exploring PEGTL's behavior. This completes the implementation using the parse tree approach that was always the goal: the grammar parses into a tree, and a TreeWalker reconstructs the demangled output by walking it. Split into three files by concern: grammar (PEG rules derived from the Itanium C++ ABI spec), selector (which rules create tree nodes), and walker (tree traversal + public API). Fix grammar bugs found during implementation: operator new/delete had spurious type parameters, template_type ordering vs template_param, lambda_sig structure, template arg pack used I...E instead of J...E. Update PEGTL API from mark() to auto_rewind(). Add GCC dot-suffix fallback for coroutine frame symbols. 48 tests covering functions, operators, templates, nested names, substitutions, lambdas, vtables, guard variables, coroutines, variadic templates, and real psyqo symbols from the torus example. Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
logical_or_operator was encoded as 'or' (which is bitwise OR) instead of 'oo'. The rule was both wrong and unreachable, shadowed by bitwise_or_operator in the sor. Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
Add a "Demangle C++" toggle (enabled by default) to the debug settings. When enabled, symbol names are demangled at display time in the assembly view (labels, jump targets, branch destinations, tooltips, symbol browser) and callstack view. Raw mangled names are preserved in the symbol table. Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@compile_flags.txt`:
- Line 20: The single-line compiler argument "-Ithird_party/ucl
-Ithird_party/ucl/include" is malformed; update compile_flags.txt so each
include flag is its own line (i.e., split into two separate entries:
"-Ithird_party/ucl" and "-Ithird_party/ucl/include") so clang/clangd/clang-tidy
treat them as distinct compiler arguments.
In `@src/gui/widgets/assembly.cc`:
- Around line 47-53: The displaySymbol helper currently calls
PCSX::GNUDemangler::demangle on every invocation (used heavily in draw()),
causing slowness; change it to look up a memoized map of raw -> demangled
strings (e.g., a static or class-level std::unordered_map) and only call
PCSX::GNUDemangler::demangle when the raw symbol is not in the cache, returning
the cached value thereafter; honor DebugSettings::DemangledSymbols by returning
the raw symbol if disabled and ensure the cache is invalidated/cleared when
DemangledSymbols is toggled or when symbols are reloaded so stale demangled
names aren’t reused.
In `@src/support/gnu-c`++-demangler-grammar.h:
- Line 328: The rule expr_primary_external_name currently uses mangled_name
which is defined to consume to pegtl::eof, causing the trailing 'E' to never be
matched; fix this by extracting the `_Z` + `encoding` sequence into a non-EOF
helper (e.g., mangled_name_inner or encoding_no_eof) and have the top-level
mangled_name remain as pegtl::seq<mangled_name_inner, pegtl::eof> while changing
expr_primary_external_name to pegtl::seq<pegtl::one<'L'>, mangled_name_inner,
pegtl::one<'E'>> so the inner parse doesn't consume EOF and the final 'E' can be
matched.
- Around line 324-325: The hexdigit rule currently uses
pegtl::string<'a','b','c','d','e','f'> which matches the literal sequence
"abcdef" instead of a single hex letter, breaking float_value
(pegtl::plus<hexdigit>). Change hexdigit to match a single hex character by
using pegtl::one<...> for the letter set and keep pegtl::digit for 0-9 (e.g.,
define hexdigit as pegtl::sor<pegtl::digit,
pegtl::one<'a','b','c','d','e','f','A','B','C','D','E','F'>> so float_value
(pegtl::plus<hexdigit>) correctly matches sequences of hex digits).
In `@src/support/gnu-c`++-demangler.cc:
- Around line 621-629: walkTemplateArgs lists trinary_operator_expression as
supported but walk() doesn't format trinary/ternary nodes, causing "qu" (?:)
template args to fall through to the generic fallback; update the walk()
function to handle trinary_operator_expression the same way
unary_operator_expression and binary_operator_expression are handled by
detecting trinary_operator_expression nodes and formatting them as a ternary
expression (condition ? true_expr : false_expr) using the node_t children order,
so walkTemplateArgs can rely on walk() to produce correct demangled output.
- Around line 27-42: The new translation unit gnu-c++-demangler.cc (providing
PCSX::GNUDemangler::demangle) is only present in the Visual Studio project so
non-MSVC builds fail to link; update the build manifests so this file is
compiled and linked by non-Visual Studio toolchains: add the
gnu-c++-demangler.cc source to the CMakeLists.txt target sources and to the
Makefile (or equivalent autoconf/Makefile.am) so the translation unit is built
into the support library or executable that provides
PCSX::GNUDemangler::demangle.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b661f8ac-1411-43ee-8180-78d80d1461d1
📒 Files selected for processing (15)
LICENSES.mdMakefilecompile_flags.txtsrc/core/psxemulator.hsrc/gui/widgets/assembly.ccsrc/gui/widgets/callstacks.ccsrc/support/gnu-c++-demangler-grammar.hsrc/support/gnu-c++-demangler-selector.hsrc/support/gnu-c++-demangler.ccsrc/support/gnu-c++-demangler.htests/support/gnu-c++-demangler.ccvsprojects/common.propsvsprojects/pcsx-redux.slnvsprojects/support/support.vcxprojvsprojects/support/support.vcxproj.filters
✅ Files skipped from review due to trivial changes (4)
- Makefile
- vsprojects/support/support.vcxproj.filters
- LICENSES.md
- vsprojects/common.props
🚧 Files skipped from review as they are similar to previous changes (2)
- vsprojects/support/support.vcxproj
- vsprojects/pcsx-redux.sln
| -Ithird_party/zlib | ||
| -Ithird_party/md4c/src | ||
| -Ithird_party/PEGTL/include | ||
| -Ithird_party/ucl -Ithird_party/ucl/include |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For clang tooling's compile_flags.txt format, is each line treated as exactly one compiler argument, or can multiple flags be written on the same line?
💡 Result:
In compile_flags.txt, each line is treated as exactly one compiler argument (“one flag per line”). So you can’t put multiple flags on the same line and expect them to be split—-Iinc -DDEBUG on one line would be passed as a single argument containing a space, which won’t work. [1], [2]
Sources: clangd project setup docs (“one-per-line”) [1], and Clang Tooling’s FixedCompilationDatabase::loadFromFile() implementation, which reads the file as a list of lines/strings (one line → one arg) [2]. [1][2]
🏁 Script executed:
find . -name "compile_flags.txt" -type fRepository: grumpycoders/pcsx-redux
Length of output: 613
🏁 Script executed:
cat -n ./compile_flags.txt | head -30Repository: grumpycoders/pcsx-redux
Length of output: 1006
Split the two -I entries on Line 20.
compile_flags.txt treats each line as exactly one compiler argument. Keeping both include dirs on one line causes them to be passed as a single malformed argument, preventing clang/clangd/clang-tidy from recognizing either UCL search path.
Proposed fix
--Ithird_party/ucl -Ithird_party/ucl/include
+-Ithird_party/ucl
+-Ithird_party/ucl/include📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| -Ithird_party/ucl -Ithird_party/ucl/include | |
| -Ithird_party/ucl | |
| -Ithird_party/ucl/include |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@compile_flags.txt` at line 20, The single-line compiler argument
"-Ithird_party/ucl -Ithird_party/ucl/include" is malformed; update
compile_flags.txt so each include flag is its own line (i.e., split into two
separate entries: "-Ithird_party/ucl" and "-Ithird_party/ucl/include") so
clang/clangd/clang-tidy treat them as distinct compiler arguments.
| static std::string displaySymbol(const std::string& symbol) { | ||
| auto& debugSettings = PCSX::g_emulator->settings.get<PCSX::Emulator::SettingDebugSettings>(); | ||
| if (debugSettings.get<PCSX::Emulator::DebugSettings::DemangledSymbols>()) { | ||
| return PCSX::GNUDemangler::demangle(symbol); | ||
| } | ||
| return symbol; | ||
| } |
There was a problem hiding this comment.
Cache demangled names before using this helper in the render loop.
This helper reparses the symbol on every call, and draw() hits it for visible labels plus every row in the Symbols window on every frame. With DemangledSymbols defaulting to true, large maps will make the debugger UI noticeably sluggish unless the demangled form is memoized per raw symbol.
🧰 Tools
🪛 Cppcheck (2.20.0)
[error] 48-48: syntax error
(syntaxError)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/gui/widgets/assembly.cc` around lines 47 - 53, The displaySymbol helper
currently calls PCSX::GNUDemangler::demangle on every invocation (used heavily
in draw()), causing slowness; change it to look up a memoized map of raw ->
demangled strings (e.g., a static or class-level std::unordered_map) and only
call PCSX::GNUDemangler::demangle when the raw symbol is not in the cache,
returning the cached value thereafter; honor DebugSettings::DemangledSymbols by
returning the raw symbol if disabled and ensure the cache is invalidated/cleared
when DemangledSymbols is toggled or when symbols are reloaded so stale demangled
names aren’t reused.
| struct hexdigit : pegtl::sor<pegtl::digit, pegtl::string<'a', 'b', 'c', 'd', 'e', 'f'>> {}; | ||
| struct float_value : pegtl::plus<hexdigit> {}; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In PEGTL, what is the difference between pegtl::string<'a','b','c'>andpegtl::one<'a','b','c'>? Which one matches a single character from that set?
💡 Result:
tao::pegtl::string<'a','b','c'>matches the three-character sequence"abc"(i.e., it’s equivalent toseq< one<'a'>, one<'b'>, one<'c'> >). [1]tao::pegtl::one<'a','b','c'>matches a single character that is one of{ 'a', 'b', 'c' }(and consumes exactly one byte). [2]
So, the one that matches a single character from that set is pegtl::one<'a','b','c'>. [2]
Sources: [1] [2]
Fix hexdigit to match a single hex digit, not the six-character sequence "abcdef".
pegtl::string<'a', 'b', 'c', 'd', 'e', 'f'> matches the exact sequence "abcdef", not a single hex digit. This breaks float_value, which requires individual hex digits in pegtl::plus<hexdigit>. Use pegtl::one<> instead to match any single character from the set.
Fix
-struct hexdigit : pegtl::sor<pegtl::digit, pegtl::string<'a', 'b', 'c', 'd', 'e', 'f'>> {};
+struct hexdigit
+ : pegtl::sor<pegtl::digit, pegtl::one<'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'>> {};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| struct hexdigit : pegtl::sor<pegtl::digit, pegtl::string<'a', 'b', 'c', 'd', 'e', 'f'>> {}; | |
| struct float_value : pegtl::plus<hexdigit> {}; | |
| struct hexdigit | |
| : pegtl::sor<pegtl::digit, pegtl::one<'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'>> {}; | |
| struct float_value : pegtl::plus<hexdigit> {}; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/support/gnu-c`++-demangler-grammar.h around lines 324 - 325, The hexdigit
rule currently uses pegtl::string<'a','b','c','d','e','f'> which matches the
literal sequence "abcdef" instead of a single hex letter, breaking float_value
(pegtl::plus<hexdigit>). Change hexdigit to match a single hex character by
using pegtl::one<...> for the letter set and keep pegtl::digit for 0-9 (e.g.,
define hexdigit as pegtl::sor<pegtl::digit,
pegtl::one<'a','b','c','d','e','f','A','B','C','D','E','F'>> so float_value
(pegtl::plus<hexdigit>) correctly matches sequences of hex digits).
| struct float_value : pegtl::plus<hexdigit> {}; | ||
| struct expr_primary_integer : pegtl::seq<pegtl::one<'L'>, type, number, pegtl::one<'E'>> {}; | ||
| struct expr_primary_floating : pegtl::seq<pegtl::one<'L'>, type, float_value, pegtl::one<'E'>> {}; | ||
| struct expr_primary_external_name : pegtl::seq<pegtl::one<'L'>, mangled_name, pegtl::one<'E'>> {}; |
There was a problem hiding this comment.
expr_primary_external_name cannot match as written.
Line 328 nests mangled_name, but Line 78 already terminates that rule with pegtl::eof. The inner parse reaches EOF before the trailing E, so every L <mangled-name> E expression primary is rejected. Please split _Z + encoding into a non-EOF helper rule and reuse that here.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/support/gnu-c`++-demangler-grammar.h at line 328, The rule
expr_primary_external_name currently uses mangled_name which is defined to
consume to pegtl::eof, causing the trailing 'E' to never be matched; fix this by
extracting the `_Z` + `encoding` sequence into a non-EOF helper (e.g.,
mangled_name_inner or encoding_no_eof) and have the top-level mangled_name
remain as pegtl::seq<mangled_name_inner, pegtl::eof> while changing
expr_primary_external_name to pegtl::seq<pegtl::one<'L'>, mangled_name_inner,
pegtl::one<'E'>> so the inner parse doesn't consume EOF and the final 'E' can be
matched.
| #include "support/gnu-c++-demangler.h" | ||
|
|
||
| #include <cctype> | ||
| #include <iostream> | ||
| #include <string> | ||
| #include <string_view> | ||
| #include <tao/pegtl.hpp> | ||
| #include <tao/pegtl/contrib/analyze.hpp> | ||
| #include <tao/pegtl/contrib/parse_tree.hpp> | ||
| #include <tao/pegtl/contrib/parse_tree_to_dot.hpp> | ||
| #include <tao/pegtl/contrib/trace.hpp> | ||
| #include <vector> | ||
|
|
||
| #include "support/gnu-c++-demangler-grammar.h" | ||
| #include "support/gnu-c++-demangler-selector.h" | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
fd -a -i 'Makefile|CMakeLists\.txt|.*\.mk|.*\.cmake|.*\.vcxproj|.*\.props' . | while read -r file; do
printf '\n== %s ==\n' "$file"
rg -n --color=never 'gnu-c\+\+-demangler\.cc' "$file" || true
doneRepository: grumpycoders/pcsx-redux
Length of output: 10015
Add src/support/gnu-c++-demangler.cc to non-Visual Studio build manifests.
src/gui/widgets/assembly.cc and src/gui/widgets/callstacks.cc now link against PCSX::GNUDemangler::demangle(...), but the build wiring is incomplete: the file is only referenced in Visual Studio project files (vsprojects/support/support.vcxproj). CMakeLists.txt and Makefile-based builds do not include this translation unit, causing link failures with unresolved demangler symbols on Linux and macOS.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/support/gnu-c`++-demangler.cc around lines 27 - 42, The new translation
unit gnu-c++-demangler.cc (providing PCSX::GNUDemangler::demangle) is only
present in the Visual Studio project so non-MSVC builds fail to link; update the
build manifests so this file is compiled and linked by non-Visual Studio
toolchains: add the gnu-c++-demangler.cc source to the CMakeLists.txt target
sources and to the Makefile (or equivalent autoconf/Makefile.am) so the
translation unit is built into the support library or executable that provides
PCSX::GNUDemangler::demangle.
| std::string walkTemplateArgs(const node_t& n) { | ||
| std::string result = "<"; | ||
| for (size_t i = 0; i < n.children.size(); i++) { | ||
| if (i > 0) result += ", "; | ||
| auto& child = *n.children[i]; | ||
| if (child.is_type<expr_primary_integer>() || child.is_type<template_arg_expression>() || | ||
| child.is_type<binary_operator_expression>() || child.is_type<unary_operator_expression>() || | ||
| child.is_type<trinary_operator_expression>()) { | ||
| result += walk(child); |
There was a problem hiding this comment.
?: template arguments still fall through to the generic fallback.
walkTemplateArgs() treats trinary_operator_expression as supported, but walk() only formats unary and binary expression nodes. Today a valid qu expression is emitted by concatenating children, so demangling is wrong instead of merely incomplete.
🛠️ Possible fix
if (n.is_type<binary_operator_expression>()) {
if (n.children.size() >= 3) {
return "(" + walk(*n.children[1]) + ")" + operatorSymbol(*n.children[0]) + "(" +
walk(*n.children[2]) + ")";
}
return "??";
}
+ if (n.is_type<trinary_operator_expression>()) {
+ if (n.children.size() >= 4) {
+ return "(" + walk(*n.children[1]) + ") ? (" + walk(*n.children[2]) + ") : (" +
+ walk(*n.children[3]) + ")";
+ }
+ return "??";
+ }
+
if (n.is_type<unary_operator_expression>()) {
if (n.children.size() >= 2) {
return operatorSymbol(*n.children[0]) + "(" + walk(*n.children[1]) + ")";
}
return "??";🧰 Tools
🪛 GitHub Check: CodeScene Code Health Review (main)
[warning] 626-627: ❌ New issue: Complex Conditional
walkTemplateArgs has 1 complex conditionals with 4 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/support/gnu-c`++-demangler.cc around lines 621 - 629, walkTemplateArgs
lists trinary_operator_expression as supported but walk() doesn't format
trinary/ternary nodes, causing "qu" (?:) template args to fall through to the
generic fallback; update the walk() function to handle
trinary_operator_expression the same way unary_operator_expression and
binary_operator_expression are handled by detecting trinary_operator_expression
nodes and formatting them as a ternary expression (condition ? true_expr :
false_expr) using the node_t children order, so walkTemplateArgs can rely on
walk() to produce correct demangled output.
Symbols like _GLOBAL__sub_I_<name> and _GLOBAL__sub_D_<name> are GCC wrappers for static initialization and cleanup. Strip the prefix, demangle the inner symbol, and present as "global constructors/ destructors keyed to <demangled>". Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
Add L<source-name> (internal linkage) to unqualified_name grammar. This handles symbols like _ZN5psyqo6KernelL24fastEnterCriticalSectionEv where the L marks a name with internal linkage. Strip __tcf prefix from GCC thread-safe static cleanup functions, demangle the inner symbol, and present as "cleanup for <demangled>". Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
The demangler depends on PEGTL but it wasn't listed in pcsx-redux.nix, so the Nix flake build couldn't find tao/pegtl.hpp. Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
Resolve conflict in pcsx-redux.nix: upstream moved stb from submodule to nixpkgs, we added PEGTL as submodule. Keep both changes. Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
The merge conflict resolution incorrectly dropped the stb submodule entry. Both PEGTL (new) and stb (existing) need to be in the list. Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
No description provided.