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..b122b27 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,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() { @@ -2085,6 +2099,13 @@ fn parse_fields_named<'de>( 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() { @@ -5113,6 +5134,40 @@ mod tests { } } + #[test] + fn parse_constructor_init_list_template_base() { + // 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] { + 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(); };");