From 223c16bdb99d846b1e6fd763860b4ee8f314ade4 Mon Sep 17 00:00:00 2001 From: Niclas Date: Mon, 8 Jun 2026 20:27:09 +0200 Subject: [PATCH] fix: parse explicit destructor calls with template arguments The destructor-id in an explicit destructor call may name a class template specialization, e.g. `p->~vector()` or `p->~shared_ptr()`. `destructor_name` only allowed `~ identifier`, so any template-id after `~` produced an ERROR node. Allow an optional `template_argument_list` and add a GLR conflict for `destructor_name` to resolve the `<` (template-args vs less-than) ambiguity. A plain `~Name` is unchanged. --- grammar.js | 3 +- test/corpus/expressions.txt | 56 +++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/grammar.js b/grammar.js index ffbaf0f..36d2343 100644 --- a/grammar.js +++ b/grammar.js @@ -105,6 +105,7 @@ module.exports = grammar(C, { [$.qualified_field_identifier, $.template_method, $.template_type], [$.type_specifier, $.template_type, $.template_function, $.expression], [$.splice_type_specifier, $.splice_expression], + [$.destructor_name], ], inline: ($, original) => original.concat([ @@ -1379,7 +1380,7 @@ module.exports = grammar(C, { ')', ), - destructor_name: $ => prec(1, seq('~', $.identifier)), + destructor_name: $ => prec(1, seq('~', $.identifier, optional($.template_argument_list))), compound_literal_expression: ($, original) => choice( original, diff --git a/test/corpus/expressions.txt b/test/corpus/expressions.txt index 96a6c26..b627515 100644 --- a/test/corpus/expressions.txt +++ b/test/corpus/expressions.txt @@ -1723,3 +1723,59 @@ template void negateValues(Args... args) { (identifier))) (string_literal (string_content)))))))))) + +================================================================================ +Explicit destructor calls with template arguments +================================================================================ + +int main() { + a->~Baz(); + b.~Qux(); + c->~Box>(); +} + +-------------------------------------------------------------------------------- + +(translation_unit + (function_definition + (primitive_type) + (function_declarator + (identifier) + (parameter_list)) + (compound_statement + (expression_statement + (call_expression + (field_expression + (identifier) + (destructor_name + (identifier) + (template_argument_list + (type_descriptor + (primitive_type))))) + (argument_list))) + (expression_statement + (call_expression + (field_expression + (identifier) + (destructor_name + (identifier) + (template_argument_list + (type_descriptor + (primitive_type)) + (type_descriptor + (primitive_type))))) + (argument_list))) + (expression_statement + (call_expression + (field_expression + (identifier) + (destructor_name + (identifier) + (template_argument_list + (type_descriptor + (template_type + (type_identifier) + (template_argument_list + (type_descriptor + (primitive_type)))))))) + (argument_list))))))