Merge pull request #7591 from jakobandersen/cpp_trailing_return

C++, parse trailing return types
This commit is contained in:
Jakob Lykke Andersen 2020-05-01 22:28:52 +02:00 committed by GitHub
commit 78491b1244
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 8 deletions

View File

@ -64,6 +64,7 @@ Features added
* C and C++: allow semicolon in the end of declarations.
* C++, parse parameterized noexcept specifiers.
* #7294: C++, parse expressions with user-defined literals.
* C++, parse trailing return types.
* #7143: py domain: Add ``:final:`` option to :rst:dir:`py:class:`,
:rst:dir:`py:exception:` and :rst:dir:`py:method:` directives

View File

@ -1871,13 +1871,14 @@ class ASTNoexceptSpec(ASTBase):
class ASTParametersQualifiers(ASTBase):
def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool,
refQual: str, exceptionSpec: ASTNoexceptSpec, override: bool, final: bool,
initializer: str) -> None:
refQual: str, exceptionSpec: ASTNoexceptSpec, trailingReturn: "ASTType",
override: bool, final: bool, initializer: str) -> None:
self.args = args
self.volatile = volatile
self.const = const
self.refQual = refQual
self.exceptionSpec = exceptionSpec
self.trailingReturn = trailingReturn
self.override = override
self.final = final
self.initializer = initializer
@ -1932,6 +1933,9 @@ class ASTParametersQualifiers(ASTBase):
if self.exceptionSpec:
res.append(' ')
res.append(transform(self.exceptionSpec))
if self.trailingReturn:
res.append(' -> ')
res.append(transform(self.trailingReturn))
if self.final:
res.append(' final')
if self.override:
@ -1970,6 +1974,9 @@ class ASTParametersQualifiers(ASTBase):
if self.exceptionSpec:
signode += nodes.Text(' ')
self.exceptionSpec.describe_signature(signode, mode, env, symbol)
if self.trailingReturn:
signode += nodes.Text(' -> ')
self.trailingReturn.describe_signature(signode, mode, env, symbol)
if self.final:
_add_anno(signode, 'final')
if self.override:
@ -2179,6 +2186,10 @@ class ASTDeclarator(ASTBase):
def function_params(self) -> List[ASTFunctionParameter]:
raise NotImplementedError(repr(self))
@property
def trailingReturn(self) -> "ASTType":
raise NotImplementedError(repr(self))
def require_space_after_declSpecs(self) -> bool:
raise NotImplementedError(repr(self))
@ -2222,6 +2233,10 @@ class ASTDeclaratorNameParamQual(ASTDeclarator):
def function_params(self) -> List[ASTFunctionParameter]:
return self.paramQual.function_params
@property
def trailingReturn(self) -> "ASTType":
return self.paramQual.trailingReturn
# only the modifiers for a function, e.g.,
def get_modifiers_id(self, version: int) -> str:
# cv-qualifiers
@ -2339,6 +2354,10 @@ class ASTDeclaratorPtr(ASTDeclarator):
def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
@property
def trailingReturn(self) -> "ASTType":
return self.next.trailingReturn
def require_space_after_declSpecs(self) -> bool:
return self.next.require_space_after_declSpecs()
@ -2438,6 +2457,10 @@ class ASTDeclaratorRef(ASTDeclarator):
def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
@property
def trailingReturn(self) -> "ASTType":
return self.next.trailingReturn
def require_space_after_declSpecs(self) -> bool:
return self.next.require_space_after_declSpecs()
@ -2494,6 +2517,10 @@ class ASTDeclaratorParamPack(ASTDeclarator):
def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
@property
def trailingReturn(self) -> "ASTType":
return self.next.trailingReturn
def require_space_after_declSpecs(self) -> bool:
return False
@ -2550,6 +2577,10 @@ class ASTDeclaratorMemPtr(ASTDeclarator):
def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
@property
def trailingReturn(self) -> "ASTType":
return self.next.trailingReturn
def require_space_after_declSpecs(self) -> bool:
return True
@ -2638,6 +2669,10 @@ class ASTDeclaratorParen(ASTDeclarator):
def function_params(self) -> List[ASTFunctionParameter]:
return self.inner.function_params
@property
def trailingReturn(self) -> "ASTType":
return self.inner.trailingReturn
def require_space_after_declSpecs(self) -> bool:
return True
@ -2766,6 +2801,10 @@ class ASTType(ASTBase):
def function_params(self) -> List[ASTFunctionParameter]:
return self.decl.function_params
@property
def trailingReturn(self) -> "ASTType":
return self.decl.trailingReturn
def get_id(self, version: int, objectType: str = None,
symbol: "Symbol" = None) -> str:
if version == 1:
@ -2802,7 +2841,10 @@ class ASTType(ASTBase):
templ = symbol.declaration.templatePrefix
if templ is not None:
typeId = self.decl.get_ptr_suffix_id(version)
returnTypeId = self.declSpecs.get_id(version)
if self.trailingReturn:
returnTypeId = self.trailingReturn.get_id(version)
else:
returnTypeId = self.declSpecs.get_id(version)
res.append(typeId)
res.append(returnTypeId)
res.append(self.decl.get_param_id(version))
@ -5575,9 +5617,6 @@ class DefinitionParser(BaseParser):
refQual = '&'
exceptionSpec = None
override = None
final = None
initializer = None
self.skip_ws()
if self.skip_string('noexcept'):
if self.skip_string_and_ws('('):
@ -5588,6 +5627,13 @@ class DefinitionParser(BaseParser):
exceptionSpec = ASTNoexceptSpec(expr)
else:
exceptionSpec = ASTNoexceptSpec(None)
self.skip_ws()
if self.skip_string('->'):
trailingReturn = self._parse_type(named=False)
else:
trailingReturn = None
self.skip_ws()
override = self.skip_word_and_ws('override')
final = self.skip_word_and_ws('final')
@ -5596,6 +5642,7 @@ class DefinitionParser(BaseParser):
'override') # they can be permuted
self.skip_ws()
initializer = None
if self.skip_string('='):
self.skip_ws()
valid = ('0', 'delete', 'default')
@ -5609,8 +5656,8 @@ class DefinitionParser(BaseParser):
% '" or "'.join(valid))
return ASTParametersQualifiers(
args, volatile, const, refQual, exceptionSpec, override, final,
initializer)
args, volatile, const, refQual, exceptionSpec, trailingReturn,
override, final, initializer)
def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple:
"""Just parse the simple ones."""

View File

@ -564,6 +564,21 @@ def test_function_definitions():
check('function', 'template<typename T> C()', {2: 'I0E1Cv'})
check('function', 'template<typename T> operator int()', {1: None, 2: 'I0Ecviv'})
# trailing return types
ids = {1: 'f', 2: '1fv'}
check('function', 'int f()', ids)
check('function', 'auto f() -> int', ids)
check('function', 'virtual auto f() -> int = 0', ids)
check('function', 'virtual auto f() -> int final', ids)
check('function', 'virtual auto f() -> int override', ids)
ids = {2: 'I0E1fv', 4: 'I0E1fiv'}
check('function', 'template<typename T> int f()', ids)
check('function', 'template<typename T> f() -> int', ids)
# from breathe#441
check('function', 'auto MakeThingy() -> Thingy*', {1: 'MakeThingy', 2: '10MakeThingyv'})
def test_operators():
check('function', 'void operator new()', {1: "new-operator", 2: "nwv"})