Skip to content

Adding GNU C++ demangler#1834

Merged
nicolasnoble merged 15 commits intogrumpycoders:mainfrom
nicolasnoble:demangle
Apr 14, 2026
Merged

Adding GNU C++ demangler#1834
nicolasnoble merged 15 commits intogrumpycoders:mainfrom
nicolasnoble:demangle

Conversation

@nicolasnoble
Copy link
Copy Markdown
Member

No description provided.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 7, 2025

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Demangler Core Implementation
src/support/gnu-c++-demangler.h, src/support/gnu-c++-demangler.cc
New public demangler API with four functions: internalCheck(), trace(), printDot(), and demangle(). Implementation includes TreeWalker class that traverses PEGTL parse trees to construct demangled C++ symbols, handling builtins, operators, templates, substitutions, pointers/references, and special constructs like lambdas and vtables.
Demangler Grammar and Parsing
src/support/gnu-c++-demangler-grammar.h, src/support/gnu-c++-demangler-selector.h
Grammar header defines comprehensive PEGTL rule set for Itanium C++ ABI mangled name parsing with custom source_name rule for length-prefixed identifiers. Selector header curates which grammar rules create parse-tree nodes via DemanglerSelector specializations for structural and leaf nodes.
Build System - POSIX
Makefile, compile_flags.txt
Extended C++ compilation flags to include PEGTL headers (-Ithird_party/PEGTL/include), updated C++ standard from c++2a to c++2b, and adjusted third-party include paths (added ELFIO, md4c, uriparser; replaced http-parser with libelfin; removed/consolidated ucl, libuv, zlib).
Build System - Visual Studio
vsprojects/common.props, vsprojects/pcsx-redux.sln, vsprojects/support/support.vcxproj, vsprojects/support/support.vcxproj.filters, vsprojects/tests/support/testsupport.vcxproj
Updated Visual Studio project configurations to include demangler source/header files in compilation, added PEGTL include path to common properties, configured /bigobj flag for demangler compilation on x64 builds, and restructured solution folders to organize PEGTL header hierarchy.
Configuration and Documentation
LICENSES.md, src/core/psxemulator.h
Added PEGTL license entry and new boolean DemangledSymbols setting (default true) to DebugSettings for controlling symbol display behavior.
GUI Integration
src/gui/widgets/assembly.cc, src/gui/widgets/callstacks.cc
Integrated demangling into assembly and callstack display: both widgets conditionally demangle symbols based on DebugSettings::DemangledSymbols setting. Assembly widget updated symbol rendering in labels and added "Demangle C++" GUI checkbox; callstack widget updated drawSymbol() to select between demangled and raw names.
Test Suite
tests/support/gnu-c++-demangler.cc
New Google Test file with 40+ test cases validating PCSX::GNUDemangler::demangle() against expected demangled output for functions, operators, templates, lambda closures, typeinfo, vtables, and real-world mangled symbols.

Sequence Diagrams

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #1867: Modifies src/gui/widgets/assembly.cc for symbol lookup and rendering logic that this PR extends with demangling support.
  • PR #1868: Updates src/gui/widgets/callstacks.cc to add drawSymbol() functionality that this PR integrates with conditional demangling.

Poem

🐰 A symbol walks into a parser, all tangled and mangled and long,
The PEGTL unweaves it with grammar so neat, a demangling song!
TreeWalker hops through, rebuilds it anew,
Now C++ symbols are crystal and true!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to evaluate whether it relates to the changeset. Add a pull request description explaining the purpose, benefits, and any relevant context for the GNU C++ demangler implementation.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Adding GNU C++ demangler' clearly and concisely summarizes the main change: introducing a GNU C++ symbol demangler implementation across header, source, grammar, tests, and build configuration files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/support/gnu-c++-demangler.cc (1)

366-371: Enhance error handling in the demangle function.

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), and demangle(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

📥 Commits

Reviewing files that changed from the base of the PR and between e6f816d and 1e1cc98.

📒 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 to AdditionalIncludeDirectories. 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 dependency

The 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 conventions

The gnu-c++-demangler.h header is properly integrated into the project structure.


213-215: Verify if /bigobj is needed for other configurations

The /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 integration

The PEGTL root folder is properly added under third_party with the main header.


780-785: LGTM! Proper nesting of PEGTL components

The folder hierarchy correctly organizes PEGTL components (core, contrib, internal) maintaining clean project structure.


789-789: Update SolutionGuid to maintain solution identity

The solution GUID has been updated, which is expected when adding new projects.

Comment on lines +103 to +104
size *= 10;
size += in.peek_char() - '0';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Comment on lines +102 to +105
while (in.size() > 0 && std::isdigit(in.peek_char())) {
size *= 10;
size += in.peek_char() - '0';
in.bump(1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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);

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. Using platform-specific debug break mechanisms (e.g., raise(SIGTRAP) on Unix).
  2. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e1cc98 and f433a31.

📒 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 issue

Fix potential issues in source_name implementation.

The source_name implementation has several issues:

  1. Integer overflow possible in size calculation
  2. Unsafe usage of std::isdigit
  3. 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.

Comment on lines +36 to +39
bool internalCheck();
bool trace(std::string_view mangled);
bool printDot(std::string_view mangled);
std::string demangle(std::string_view mangled);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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);


MIT License

Copyright (c) 2025 PCSX-Redux authors
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
Copyright (c) 2025 PCSX-Redux authors
Copyright (c) 2024 PCSX-Redux authors

Comment on lines +58 to +63
struct DemanglerState {
std::string tostring() { return ""; }
std::vector<std::string> bag;
std::string_view lastName;
const std::type_info* lastAction;
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve DemanglerState implementation.

The DemanglerState class needs improvements:

  1. tostring() returns an empty string but should format the state.
  2. Member variables lack documentation.
  3. 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
};

Comment on lines +382 to +1870
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");
}
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling in DemanglerAction implementations.

The current implementation has several issues:

  1. All actions throw exceptions, making error recovery impossible
  2. No progress tracking or partial results
  3. Debug breaks in every action make debugging cumbersome

Consider implementing a more robust error handling strategy:

  1. 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();
        }
    }
};
  1. 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;
};

Comment on lines +1894 to +1905
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);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling in demangle function.

The current implementation has several issues:

  1. Silently catches all exceptions
  2. Only prints unimplemented rule names
  3. 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
        };
    }
}

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between f433a31 and 12443a5.

📒 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:

  1. tostring() returns an empty string but is used in demangle()
  2. Member variables lack documentation
  3. Consider making tostring() const-qualified

138-140: Check for potential integer overflow in size calculation.

The size variable is calculated by accumulating digit characters. If the mangled name contains a very large number, there is a risk of integer overflow.


138-141: Cast char to unsigned char when using std::isdigit.

Using std::isdigit with char can lead to undefined behavior if char is signed and contains a negative value.


382-1870: Improve error handling in DemanglerAction implementations.

The current implementation has several issues:

  1. All actions throw exceptions, making error recovery impossible
  2. No progress tracking or partial results
  3. Debug breaks in every action make debugging cumbersome

1894-1905: Improve error handling in demangle function.

The current implementation has several issues:

  1. Silently catches all exceptions
  2. Only prints unimplemented rule names
  3. Always returns the original mangled name on failure

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
src/support/gnu-c++-demangler.cc (5)

61-66: 🛠️ Refactor suggestion

Improve DemanglerState implementation.

The DemanglerState class needs improvements:

  1. tostring() returns an empty string but should format the state.
  2. Member variables lack documentation.
  3. 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 issue

Check for potential integer overflow in size calculation.

The size variable 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 issue

Cast char to unsigned char when using std::isdigit.

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.

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 suggestion

Improve error handling in DemanglerAction implementations.

The current implementation has several issues:

  1. All actions throw exceptions, making error recovery impossible
  2. No progress tracking or partial results
  3. 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 suggestion

Improve error handling in demangle function.

The current implementation has several issues:

  1. Silently catches all exceptions
  2. Only prints unimplemented rule names
  3. 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:

  1. Add comments explaining the mangling patterns for complex cases (e.g., lines 55-57 with template arithmetic).
  2. 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 /bigobj compiler option is correctly added for the demangler, which suggests it generates many symbols. Consider:

  1. Adding a comment explaining why this option is needed
  2. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 12443a5 and bfd9f4a.

📒 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:

  1. All development environments support C++2b features
  2. 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 cpp

Length of output: 37200

src/support/gnu-c++-demangler.cc (1)

52-58: LGTM!

The debug utilities are properly implemented with platform-specific handling.

nicolasnoble and others added 10 commits April 6, 2026 21:41
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>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between bfd9f4a and 024a45e.

📒 Files selected for processing (15)
  • LICENSES.md
  • Makefile
  • compile_flags.txt
  • src/core/psxemulator.h
  • src/gui/widgets/assembly.cc
  • src/gui/widgets/callstacks.cc
  • src/support/gnu-c++-demangler-grammar.h
  • src/support/gnu-c++-demangler-selector.h
  • src/support/gnu-c++-demangler.cc
  • src/support/gnu-c++-demangler.h
  • tests/support/gnu-c++-demangler.cc
  • vsprojects/common.props
  • vsprojects/pcsx-redux.sln
  • vsprojects/support/support.vcxproj
  • vsprojects/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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 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 f

Repository: grumpycoders/pcsx-redux

Length of output: 613


🏁 Script executed:

cat -n ./compile_flags.txt | head -30

Repository: 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.

Suggested change
-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.

Comment on lines +47 to +53
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;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +324 to +325
struct hexdigit : pegtl::sor<pegtl::digit, pegtl::string<'a', 'b', 'c', 'd', 'e', 'f'>> {};
struct float_value : pegtl::plus<hexdigit> {};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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 to seq< 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.

Suggested change
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'>> {};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +27 to +42
#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"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 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
done

Repository: 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.

Comment on lines +621 to +629
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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

?: 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>
@nicolasnoble nicolasnoble merged commit 2797eab into grumpycoders:main Apr 14, 2026
18 of 20 checks passed
@nicolasnoble nicolasnoble deleted the demangle branch April 14, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant