diff --git a/cxxheaderparser/parser.py b/cxxheaderparser/parser.py index 41b7a54..d633e2a 100644 --- a/cxxheaderparser/parser.py +++ b/cxxheaderparser/parser.py @@ -718,6 +718,17 @@ def _parse_template_specialization(self) -> TemplateSpecialization: if dtype: args.append(TemplateArgument(dtype, param_pack)) else: + # special case for sizeof...(thing) + if ( + param_pack + and len(val.tokens) == 1 + and val.tokens[0].value == "sizeof" + ): + val.tokens.append(Token("...", "ELLIPSIS")) + tok = self._next_token_must_be("(") + raw_toks = self._consume_balanced_tokens(tok) + val.tokens.extend(Token(tok.value, tok.type) for tok in raw_toks) + args.append(TemplateArgument(val, param_pack)) tok = self._next_token_must_be(",", ">") @@ -2624,6 +2635,16 @@ def _parse_declarations( ): return + # Check for an abbreviated template return type, promote it + if not is_typedef and parsed_type is not None and self.lex.token_if_val("auto"): + abv_ret_tmpl = TemplateNonTypeParam(type=parsed_type, param_idx=-1) + if template is None: + template = TemplateDecl(params=[abv_ret_tmpl]) + elif isinstance(template, TemplateDecl): + template.params.append(abv_ret_tmpl) + else: + template[-1].params.append(abv_ret_tmpl) + var_ok = True if is_typedef: diff --git a/cxxheaderparser/types.py b/cxxheaderparser/types.py index 1aa0b99..59169fc 100644 --- a/cxxheaderparser/types.py +++ b/cxxheaderparser/types.py @@ -458,13 +458,18 @@ class TemplateNonTypeParam: // abbreviated template parameters are converted to this and param_idx is set void fn(C auto p) ~~~~~~ + + // abbreviated template parameters that are return types have param_idx = -1 + C auto fn() + ~~~~~~ """ type: DecoratedType name: typing.Optional[str] = None default: typing.Optional[Value] = None - #: If this was promoted, the parameter index that this corresponds with + #: If this was promoted, the parameter index that this corresponds with. Return + #: types are set to -1 param_idx: typing.Optional[int] = None #: Contains a ``...`` diff --git a/tests/test_abv_template.py b/tests/test_abv_template.py index 288c2d3..67b1cf8 100644 --- a/tests/test_abv_template.py +++ b/tests/test_abv_template.py @@ -351,3 +351,77 @@ def test_abv_template_f5() -> None: ] ) ) + + +def test_returned_abv_template() -> None: + content = """ + constexpr std::signed_integral auto FloorDiv(std::signed_integral auto x, + std::signed_integral auto y); + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + functions=[ + Function( + return_type=Type( + typename=PQName( + segments=[ + NameSpecifier(name="std"), + NameSpecifier(name="signed_integral"), + ] + ) + ), + name=PQName(segments=[NameSpecifier(name="FloorDiv")]), + parameters=[ + Parameter( + type=Type(typename=PQName(segments=[AutoSpecifier()])), + name="x", + ), + Parameter( + type=Type(typename=PQName(segments=[AutoSpecifier()])), + name="y", + ), + ], + constexpr=True, + template=TemplateDecl( + params=[ + TemplateNonTypeParam( + type=Type( + typename=PQName( + segments=[ + NameSpecifier(name="std"), + NameSpecifier(name="signed_integral"), + ] + ) + ), + param_idx=-1, + ), + TemplateNonTypeParam( + type=Type( + typename=PQName( + segments=[ + NameSpecifier(name="std"), + NameSpecifier(name="signed_integral"), + ] + ) + ), + param_idx=0, + ), + TemplateNonTypeParam( + type=Type( + typename=PQName( + segments=[ + NameSpecifier(name="std"), + NameSpecifier(name="signed_integral"), + ] + ) + ), + param_idx=1, + ), + ] + ), + ) + ] + ) + ) diff --git a/tests/test_template.py b/tests/test_template.py index ffdf8e9..cee092d 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -2247,3 +2247,108 @@ def test_template_deduction_guide() -> None: ] ) ) + + +def test_sizeof_pack() -> None: + content = """ + template ... OutputIndices> + LinearSystem Slice(OutputIndices... outputIndices); + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + functions=[ + Function( + return_type=Type( + typename=PQName( + segments=[ + NameSpecifier( + name="LinearSystem", + specialization=TemplateSpecialization( + args=[ + TemplateArgument( + arg=Type( + typename=PQName( + segments=[ + NameSpecifier(name="States") + ] + ) + ) + ), + TemplateArgument( + arg=Type( + typename=PQName( + segments=[ + NameSpecifier(name="Inputs") + ] + ) + ) + ), + TemplateArgument( + arg=Value( + tokens=[ + Token(value="sizeof"), + Token(value="..."), + Token(value="("), + Token(value="OutputIndices"), + Token(value=")"), + ] + ), + param_pack=True, + ), + ] + ), + ) + ] + ) + ), + name=PQName(segments=[NameSpecifier(name="Slice")]), + parameters=[ + Parameter( + type=Type( + typename=PQName( + segments=[NameSpecifier(name="OutputIndices")] + ) + ), + name="outputIndices", + param_pack=True, + ) + ], + template=TemplateDecl( + params=[ + TemplateNonTypeParam( + type=Type( + typename=PQName( + segments=[ + NameSpecifier(name="std"), + NameSpecifier( + name="same_as", + specialization=TemplateSpecialization( + args=[ + TemplateArgument( + arg=Type( + typename=PQName( + segments=[ + FundamentalSpecifier( + name="int" + ) + ] + ) + ) + ) + ] + ), + ), + ] + ) + ), + name="OutputIndices", + param_pack=True, + ) + ] + ), + ) + ] + ) + )