Skip to content

Commit 7db87aa

Browse files
authored
Merge pull request #117 from robotpy/multiple-gcc-attributes
Allow multiple GCC attributes chained together
2 parents c5ca9aa + 0607e40 commit 7db87aa

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

cxxheaderparser/parser.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -901,11 +901,17 @@ def _consume_attribute(self, tok: LexToken) -> None:
901901
raise CxxParseError("internal error")
902902

903903
def _consume_gcc_attribute(
904-
self, tok: LexToken, doxygen: typing.Optional[str] = None
904+
self, tok: typing.Optional[LexToken], doxygen: typing.Optional[str] = None
905905
) -> None:
906-
tok1 = self._next_token_must_be("(")
907-
tok2 = self._next_token_must_be("(")
908-
self._consume_balanced_tokens(tok1, tok2)
906+
while True:
907+
tok1 = self._next_token_must_be("(")
908+
tok2 = self._next_token_must_be("(")
909+
self._consume_balanced_tokens(tok1, tok2)
910+
911+
# Apparently you can have multiple attributes chained together?
912+
tok = self.lex.token_if("__attribute__")
913+
if tok is None:
914+
break
909915

910916
def _consume_declspec(
911917
self, tok: LexToken, doxygen: typing.Optional[str] = None
@@ -2676,6 +2682,11 @@ def _parse_declarations(
26762682
# if it returns True then it handled the end of the statement
26772683
break
26782684

2685+
# Sometimes attributes come after a function
2686+
atok = self.lex.token_if("__attribute__")
2687+
if atok:
2688+
self._consume_gcc_attribute(atok)
2689+
26792690
# Unset the doxygen, location
26802691
doxygen = None
26812692

tests/test_attributes.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,34 @@ def test_declspec_template() -> None:
231231
]
232232
)
233233
)
234+
235+
236+
def test_multiple_attributes() -> None:
237+
content = """
238+
extern const unsigned short int **__ctype_b_loc (void) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__const__));
239+
"""
240+
data = parse_string(content, cleandoc=True)
241+
242+
assert data == ParsedData(
243+
namespace=NamespaceScope(
244+
functions=[
245+
Function(
246+
return_type=Pointer(
247+
ptr_to=Pointer(
248+
ptr_to=Type(
249+
typename=PQName(
250+
segments=[
251+
FundamentalSpecifier(name="unsigned short int")
252+
]
253+
),
254+
const=True,
255+
)
256+
)
257+
),
258+
name=PQName(segments=[NameSpecifier(name="__ctype_b_loc")]),
259+
parameters=[],
260+
extern=True,
261+
)
262+
]
263+
)
264+
)

0 commit comments

Comments
 (0)