From 7a4e532952b1fb02ef83a0b902893769b5b59d66 Mon Sep 17 00:00:00 2001 From: Jeremy HERGAULT Date: Thu, 30 Jul 2026 14:22:16 +0200 Subject: [PATCH 1/2] fix: handle initialize with templated argument --- Cargo.toml | 2 +- src/ast/parse.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3be4d1f..81bf71f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cppshift" -version = "0.1.2" +version = "0.1.3" authors = ["Jérémy HERGAULT", "Enzo PASQUALINI"] description = "CPP parser and transpiler" repository = "https://github.com/worldline/cppshift" diff --git a/src/ast/parse.rs b/src/ast/parse.rs index 331b8fe..1d1b4bc 100644 --- a/src/ast/parse.rs +++ b/src/ast/parse.rs @@ -1248,6 +1248,13 @@ fn parse_item_fn_or_var<'de>(p: &mut Parser<'de>) -> Result, AstError> loop { skip_macro_annotations(p)?; let member = parse_path(p)?; + // A base-class initializer may be a template-id + if p.peek_kind() == Some(TokenKind::LeftChevron) { + let cp = p.checkpoint(); + if parse_angle_bracketed_args(p).is_err() { + p.restore(&cp); + } + } p.expect(TokenKind::LeftParenthese)?; let mut args = Punctuated::new(); while p.peek_kind() != Some(TokenKind::RightParenthese) && !p.is_empty() { @@ -1569,6 +1576,14 @@ fn parse_item_fn_or_var<'de>(p: &mut Parser<'de>) -> Result, AstError> loop { skip_macro_annotations(p)?; let member = parse_path(p)?; + // A base-class initializer may be a template-id, e.g. + // `std::vector(items)`. + if p.peek_kind() == Some(TokenKind::LeftChevron) { + let cp = p.checkpoint(); + if parse_angle_bracketed_args(p).is_err() { + p.restore(&cp); + } + } p.expect(TokenKind::LeftParenthese)?; let mut args = Punctuated::new(); while p.peek_kind() != Some(TokenKind::RightParenthese) && !p.is_empty() { @@ -2085,6 +2100,14 @@ fn parse_fields_named<'de>( loop { skip_macro_annotations(p)?; let member = parse_path(p)?; + // A base-class initializer may be a template-id, e.g. + // `std::vector(items)`. + if p.peek_kind() == Some(TokenKind::LeftChevron) { + let cp = p.checkpoint(); + if parse_angle_bracketed_args(p).is_err() { + p.restore(&cp); + } + } p.expect(TokenKind::LeftParenthese)?; let mut args = Punctuated::new(); while p.peek_kind() != Some(TokenKind::RightParenthese) && !p.is_empty() { @@ -5113,6 +5136,40 @@ mod tests { } } + #[test] + fn parse_constructor_init_list_template_base() { + // A base-class initializer may be a template-id: `std::vector(items)`. + let file = + parse("class Foo : public std::vector { Foo(int x) : std::vector(x) { } };"); + match &file.items[0] { + Item::Class(c) => { + if let Fields::Named(f) = &c.fields { + match &f.members[0] { + Member::Constructor(ctor) => { + assert_eq!(ctor.member_init_list.len(), 1); + assert_eq!(ctor.member_init_list[0].member.to_string(), "std::vector"); + } + other => panic!("expected Constructor, got {other:?}"), + } + } + } + other => panic!("expected Class, got {other:?}"), + } + } + + #[test] + fn parse_qualified_constructor_init_list_template_base() { + let file = parse("Foo::Foo(int x) : std::vector(x), m_x(x) { }"); + match &file.items[0] { + Item::Fn(f) => { + assert_eq!(f.sig.member_init_list.len(), 2); + assert_eq!(f.sig.member_init_list[0].member.to_string(), "std::vector"); + assert_eq!(f.sig.member_init_list[1].member.to_string(), "m_x"); + } + other => panic!("expected Fn, got {other:?}"), + } + } + #[test] fn parse_destructor() { let file = parse("class Foo { ~Foo(); };"); From 0212886716dcbfdd88cc85881fef0b543d196bcc Mon Sep 17 00:00:00 2001 From: Jeremy HERGAULT Date: Thu, 30 Jul 2026 14:25:18 +0200 Subject: [PATCH 2/2] fix: change comments --- src/ast/parse.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ast/parse.rs b/src/ast/parse.rs index 1d1b4bc..b122b27 100644 --- a/src/ast/parse.rs +++ b/src/ast/parse.rs @@ -1576,8 +1576,7 @@ fn parse_item_fn_or_var<'de>(p: &mut Parser<'de>) -> Result, AstError> loop { skip_macro_annotations(p)?; let member = parse_path(p)?; - // A base-class initializer may be a template-id, e.g. - // `std::vector(items)`. + // A base-class initializer may be a template-id if p.peek_kind() == Some(TokenKind::LeftChevron) { let cp = p.checkpoint(); if parse_angle_bracketed_args(p).is_err() { @@ -2100,8 +2099,7 @@ fn parse_fields_named<'de>( loop { skip_macro_annotations(p)?; let member = parse_path(p)?; - // A base-class initializer may be a template-id, e.g. - // `std::vector(items)`. + // A base-class initializer may be a template-id if p.peek_kind() == Some(TokenKind::LeftChevron) { let cp = p.checkpoint(); if parse_angle_bracketed_args(p).is_err() { @@ -5138,7 +5136,7 @@ mod tests { #[test] fn parse_constructor_init_list_template_base() { - // A base-class initializer may be a template-id: `std::vector(items)`. + // A base-class initializer may be a template-id: `std::vector(x)`. let file = parse("class Foo : public std::vector { Foo(int x) : std::vector(x) { } };"); match &file.items[0] {