Did you check existing issues?
Tree-Sitter CLI Version, if relevant
tree-sitter-cpp 0.23.4, tree-sitter 0.23.2 (Python bindings)
Describe the bug
The grammar handles the named pointer-to-member declarator (void (C::*p)(int)) but has no production for the anonymous / abstract form (C::*) used in type-ids. As a result, every C++ construct whose syntax requires an abstract type-id containing a pointer-to-member fails to parse:
- alias declarations:
using F = void (C::*)(int);
sizeof(void (C::*)(int))
- C-style casts:
(void (C::*)(int))p
- (presumably) function-pointer parameter types, template arguments,
decltype, etc.
In every case, has_error is True and the parse tree contains either a MISSING "type_identifier" inside qualified_identifier or a stray abstract_pointer_declarator (*) attached as a sibling.
This bug appears to be the underlying parser misparse behind the error-recovery cascade observed in #352 (which frames the same construct as a template-call / statement-ordering recovery issue). It is distinct from #348 (C++‑style static_cast / typeid misparse) and from #102 / #113 (which fixed only the named declarator).
Steps To Reproduce / Bad Parse Tree
The cleanest reproducer is an alias declaration, because the RHS is required by the C++ grammar to be a type-id — there is no cast / call-expression ambiguity to argue about. The snippet compiles cleanly with g++ -c:
struct C;
using F = void (C::*)(int);
Parses as:
(translation_unit
(struct_specifier
(struct)
name: (type_identifier))
(;)
(alias_declaration
(using)
name: (type_identifier)
(=)
type: (type_descriptor
type: (primitive_type)
declarator: (abstract_function_declarator
declarator: (abstract_function_declarator
parameters: (parameter_list
(()
(parameter_declaration
type: (qualified_identifier
scope: (namespace_identifier)
(::)
name: (MISSING "type_identifier"))
declarator: (abstract_pointer_declarator
(*)))
())))
parameters: (parameter_list
(()
(parameter_declaration
type: (primitive_type))
()))))
(;)))
;; has_error = True
The grammar tries to interpret the inner (C::*) as a parameter_list whose sole parameter_declaration has type qualified_identifier (C::) with a MISSING type_identifier, plus an orphan abstract_pointer_declarator (*).
The same misparse appears in sizeof:
struct C;
auto s = sizeof(void (C::*)(int));
(... (sizeof_expression
(sizeof)
value: (parenthesized_expression
(()
(call_expression
function: (call_expression
function: (primitive_type)
arguments: (argument_list
(()
(qualified_identifier
scope: (namespace_identifier)
(::)
name: (pointer_type_declarator
(*)
declarator: (MISSING "type_identifier")))
())))
arguments: (argument_list
(()
(ERROR
(primitive_type))
())))
()))) ...)
;; has_error = True
And in a C-style cast:
struct C;
auto x = (void (C::*)(int))0;
(... value: (parenthesized_expression
(()
(call_expression
function: (call_expression
function: (primitive_type)
arguments: (argument_list
(()
(qualified_identifier
scope: (namespace_identifier)
(::)
name: (pointer_type_declarator
(*)
declarator: (MISSING "type_identifier")))
())))
arguments: (argument_list
(()
(ERROR
(primitive_type))
())))
())) ...)
;; has_error = True
Expected Behavior / Parse Tree
All three abstract-form snippets should parse with has_error = False. The RHS type of the alias should be a type_descriptor whose declarator is some abstract pointer-to-member declarator (mirroring the named form), roughly:
type: (type_descriptor
type: (primitive_type) ; void
declarator: (abstract_function_declarator
declarator: (abstract_parenthesized_declarator
(()
(qualified_identifier ; C::*
scope: (namespace_identifier)
(::)
name: (abstract_pointer_declarator
(*)))
()))
parameters: (parameter_list (() (parameter_declaration type: (primitive_type)) ())))) ; (int)
Did you check existing issues?
Tree-Sitter CLI Version, if relevant
tree-sitter-cpp 0.23.4, tree-sitter 0.23.2 (Python bindings)
Describe the bug
The grammar handles the named pointer-to-member declarator (
void (C::*p)(int)) but has no production for the anonymous / abstract form(C::*)used in type-ids. As a result, every C++ construct whose syntax requires an abstract type-id containing a pointer-to-member fails to parse:using F = void (C::*)(int);sizeof(void (C::*)(int))(void (C::*)(int))pdecltype, etc.In every case,
has_errorisTrueand the parse tree contains either aMISSING "type_identifier"insidequalified_identifieror a strayabstract_pointer_declarator (*)attached as a sibling.This bug appears to be the underlying parser misparse behind the error-recovery cascade observed in #352 (which frames the same construct as a template-call / statement-ordering recovery issue). It is distinct from #348 (C++‑style
static_cast/typeidmisparse) and from #102 / #113 (which fixed only the named declarator).Steps To Reproduce / Bad Parse Tree
The cleanest reproducer is an alias declaration, because the RHS is required by the C++ grammar to be a type-id — there is no cast / call-expression ambiguity to argue about. The snippet compiles cleanly with
g++ -c:Parses as:
The grammar tries to interpret the inner
(C::*)as aparameter_listwhose soleparameter_declarationhas typequalified_identifier (C::)with aMISSING type_identifier, plus an orphanabstract_pointer_declarator (*).The same misparse appears in
sizeof:And in a C-style cast:
Expected Behavior / Parse Tree
All three abstract-form snippets should parse with
has_error = False. The RHS type of the alias should be atype_descriptorwhose declarator is some abstract pointer-to-member declarator (mirroring the named form), roughly: