Skip to content

Commit

Permalink
Merge pull request #9379 from jakobandersen/cpp_various
Browse files Browse the repository at this point in the history
C++ (and C), various additions
  • Loading branch information
jakobandersen committed Jun 24, 2021
2 parents d10c9de + 450d5ca commit eda4b1c
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 58 deletions.
12 changes: 12 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ Features added
* #9097: Optimize the paralell build
* #9131: Add :confval:`nitpick_ignore_regex` to ignore nitpicky warnings using
regular expressions
* C++, add support for

- ``inline`` variables,
- ``consteval`` functions,
- ``constinit`` variables,
- ``char8_t``,
- ``explicit(<constant expression>)`` specifier,
- digit separators in literals, and
- constraints in placeholder type specifiers, aka. adjective syntax
(e.g., ``Sortable auto &v``).

* C, add support for digit separators in literals.


Bugs fixed
Expand Down
172 changes: 130 additions & 42 deletions sphinx/domains/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,9 @@
# see https://en.cppreference.com/w/cpp/keyword
_keywords = [
'alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor',
'bool', 'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class',
'compl', 'concept', 'const', 'constexpr', 'const_cast', 'continue',
'bool', 'break', 'case', 'catch', 'char', 'char8_t', 'char16_t', 'char32_t',
'class', 'compl', 'concept', 'const', 'consteval', 'constexpr', 'constinit',
'const_cast', 'continue',
'decltype', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else',
'enum', 'explicit', 'export', 'extern', 'false', 'float', 'for', 'friend',
'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new',
Expand Down Expand Up @@ -426,6 +427,7 @@
'wchar_t': 'w',
'char32_t': 'Di',
'char16_t': 'Ds',
'char8_t': 'Du',
'short': 's',
'short int': 's',
'signed short': 's',
Expand Down Expand Up @@ -1880,9 +1882,11 @@ def describe_signature(self, signode: TextElement, mode: str,


class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
def __init__(self, prefix: str, nestedName: ASTNestedName) -> None:
def __init__(self, prefix: str, nestedName: ASTNestedName,
placeholderType: Optional[str]) -> None:
self.prefix = prefix
self.nestedName = nestedName
self.placeholderType = placeholderType

@property
def name(self) -> ASTNestedName:
Expand All @@ -1897,6 +1901,9 @@ def _stringify(self, transform: StringifyTransform) -> str:
res.append(self.prefix)
res.append(' ')
res.append(transform(self.nestedName))
if self.placeholderType is not None:
res.append(' ')
res.append(self.placeholderType)
return ''.join(res)

def describe_signature(self, signode: TextElement, mode: str,
Expand All @@ -1905,6 +1912,17 @@ def describe_signature(self, signode: TextElement, mode: str,
signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
signode += addnodes.desc_sig_space()
self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
if self.placeholderType is not None:
signode += addnodes.desc_sig_space()
if self.placeholderType == 'auto':
signode += addnodes.desc_sig_keyword('auto', 'auto')
elif self.placeholderType == 'decltype(auto)':
signode += addnodes.desc_sig_keyword('decltype', 'decltype')
signode += addnodes.desc_sig_punctuation('(', '(')
signode += addnodes.desc_sig_keyword('auto', 'auto')
signode += addnodes.desc_sig_punctuation(')', ')')
else:
assert False, self.placeholderType


class ASTFunctionParameter(ASTBase):
Expand Down Expand Up @@ -2099,16 +2117,41 @@ def _add_anno(signode: TextElement, text: str) -> None:
signode += addnodes.desc_sig_keyword(self.initializer, self.initializer)


class ASTExplicitSpec(ASTBase):
def __init__(self, expr: Optional[ASTExpression]) -> None:
self.expr = expr

def _stringify(self, transform: StringifyTransform) -> str:
res = ['explicit']
if self.expr is not None:
res.append('(')
res.append(transform(self.expr))
res.append(')')
return ''.join(res)

def describe_signature(self, signode: TextElement,
env: "BuildEnvironment", symbol: "Symbol") -> None:
signode += addnodes.desc_sig_keyword('explicit', 'explicit')
if self.expr is not None:
signode += addnodes.desc_sig_punctuation('(', '(')
self.expr.describe_signature(signode, 'markType', env, symbol)
signode += addnodes.desc_sig_punctuation(')', ')')


class ASTDeclSpecsSimple(ASTBase):
def __init__(self, storage: str, threadLocal: bool, inline: bool, virtual: bool,
explicit: bool, constexpr: bool, volatile: bool, const: bool,
friend: bool, attrs: List[ASTAttribute]) -> None:
explicitSpec: Optional[ASTExplicitSpec],
consteval: bool, constexpr: bool, constinit: bool,
volatile: bool, const: bool, friend: bool,
attrs: List[ASTAttribute]) -> None:
self.storage = storage
self.threadLocal = threadLocal
self.inline = inline
self.virtual = virtual
self.explicit = explicit
self.explicitSpec = explicitSpec
self.consteval = consteval
self.constexpr = constexpr
self.constinit = constinit
self.volatile = volatile
self.const = const
self.friend = friend
Expand All @@ -2121,8 +2164,10 @@ def mergeWith(self, other: "ASTDeclSpecsSimple") -> "ASTDeclSpecsSimple":
self.threadLocal or other.threadLocal,
self.inline or other.inline,
self.virtual or other.virtual,
self.explicit or other.explicit,
self.explicitSpec or other.explicitSpec,
self.consteval or other.consteval,
self.constexpr or other.constexpr,
self.constinit or other.constinit,
self.volatile or other.volatile,
self.const or other.const,
self.friend or other.friend,
Expand All @@ -2141,17 +2186,22 @@ def _stringify(self, transform: StringifyTransform) -> str:
res.append('friend')
if self.virtual:
res.append('virtual')
if self.explicit:
res.append('explicit')
if self.explicitSpec:
res.append(transform(self.explicitSpec))
if self.consteval:
res.append('consteval')
if self.constexpr:
res.append('constexpr')
if self.constinit:
res.append('constinit')
if self.volatile:
res.append('volatile')
if self.const:
res.append('const')
return ' '.join(res)

def describe_signature(self, signode: TextElement) -> None:
def describe_signature(self, signode: TextElement,
env: "BuildEnvironment", symbol: "Symbol") -> None:
addSpace = False
for attr in self.attrs:
if addSpace:
Expand All @@ -2175,10 +2225,17 @@ def _add(signode: TextElement, text: str) -> bool:
addSpace = _add(signode, 'friend')
if self.virtual:
addSpace = _add(signode, 'virtual')
if self.explicit:
addSpace = _add(signode, 'explicit')
if self.explicitSpec:
if addSpace:
signode += addnodes.desc_sig_space()
self.explicitSpec.describe_signature(signode, env, symbol)
addSpace = True
if self.consteval:
addSpace = _add(signode, 'consteval')
if self.constexpr:
addSpace = _add(signode, 'constexpr')
if self.constinit:
addSpace = _add(signode, 'constinit')
if self.volatile:
addSpace = _add(signode, 'volatile')
if self.const:
Expand Down Expand Up @@ -2235,7 +2292,7 @@ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
verify_description_mode(mode)
numChildren = len(signode)
self.leftSpecs.describe_signature(signode)
self.leftSpecs.describe_signature(signode, env, symbol)
addSpace = len(signode) != numChildren

if self.trailingTypeSpec:
Expand All @@ -2249,7 +2306,7 @@ def describe_signature(self, signode: TextElement, mode: str,
if len(str(self.rightSpecs)) > 0:
if addSpace:
signode += addnodes.desc_sig_space()
self.rightSpecs.describe_signature(signode)
self.rightSpecs.describe_signature(signode, env, symbol)


# Declarator
Expand Down Expand Up @@ -4942,8 +4999,8 @@ class DefinitionParser(BaseParser):
# those without signedness and size modifiers
# see https://en.cppreference.com/w/cpp/language/types
_simple_fundemental_types = (
'void', 'bool', 'char', 'wchar_t', 'char16_t', 'char32_t', 'int',
'float', 'double', 'auto'
'void', 'bool', 'char', 'wchar_t', 'char8_t', 'char16_t', 'char32_t',
'int', 'float', 'double', 'auto'
)

_prefix_keys = ('class', 'struct', 'enum', 'union', 'typename')
Expand Down Expand Up @@ -5815,7 +5872,19 @@ def _parse_trailing_type_spec(self) -> ASTTrailingTypeSpec:
prefix = k
break
nestedName = self._parse_nested_name()
return ASTTrailingTypeSpecName(prefix, nestedName)
self.skip_ws()
placeholderType = None
if self.skip_word('auto'):
placeholderType = 'auto'
elif self.skip_word_and_ws('decltype'):
if not self.skip_string_and_ws('('):
self.fail("Expected '(' after 'decltype' in placeholder type specifier.")
if not self.skip_word_and_ws('auto'):
self.fail("Expected 'auto' after 'decltype(' in placeholder type specifier.")
if not self.skip_string_and_ws(')'):
self.fail("Expected ')' after 'decltype(auto' in placeholder type specifier.")
placeholderType = 'decltype(auto)'
return ASTTrailingTypeSpecName(prefix, nestedName, placeholderType)

def _parse_parameters_and_qualifiers(self, paramMode: str) -> ASTParametersQualifiers:
if paramMode == 'new':
Expand Down Expand Up @@ -5929,14 +5998,24 @@ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimpl
threadLocal = None
inline = None
virtual = None
explicit = None
explicitSpec = None
consteval = None
constexpr = None
constinit = None
volatile = None
const = None
friend = None
attrs = []
while 1: # accept any permutation of a subset of some decl-specs
self.skip_ws()
if not const and typed:
const = self.skip_word('const')
if const:
continue
if not volatile and typed:
volatile = self.skip_word('volatile')
if volatile:
continue
if not storage:
if outer in ('member', 'function'):
if self.skip_word('static'):
Expand All @@ -5952,16 +6031,28 @@ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimpl
if self.skip_word('register'):
storage = 'register'
continue
if not threadLocal and outer == 'member':
threadLocal = self.skip_word('thread_local')
if threadLocal:
if not inline and outer in ('function', 'member'):
inline = self.skip_word('inline')
if inline:
continue
if not constexpr and outer in ('member', 'function'):
constexpr = self.skip_word("constexpr")
if constexpr:
continue

if outer == 'member':
if not constinit:
constinit = self.skip_word('constinit')
if constinit:
continue
if not threadLocal:
threadLocal = self.skip_word('thread_local')
if threadLocal:
continue
if outer == 'function':
# function-specifiers
if not inline:
inline = self.skip_word('inline')
if inline:
if not consteval:
consteval = self.skip_word('consteval')
if consteval:
continue
if not friend:
friend = self.skip_word('friend')
Expand All @@ -5971,31 +6062,28 @@ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimpl
virtual = self.skip_word('virtual')
if virtual:
continue
if not explicit:
explicit = self.skip_word('explicit')
if not explicitSpec:
explicit = self.skip_word_and_ws('explicit')
if explicit:
expr: ASTExpression = None
if self.skip_string('('):
expr = self._parse_constant_expression(inTemplate=False)
if not expr:
self.fail("Expected constant expression after '('" +
" in explicit specifier.")
self.skip_ws()
if not self.skip_string(')'):
self.fail("Expected ')' to end explicit specifier.")
explicitSpec = ASTExplicitSpec(expr)
continue

if not constexpr and outer in ('member', 'function'):
constexpr = self.skip_word("constexpr")
if constexpr:
continue
if not volatile and typed:
volatile = self.skip_word('volatile')
if volatile:
continue
if not const and typed:
const = self.skip_word('const')
if const:
continue
attr = self._parse_attribute()
if attr:
attrs.append(attr)
continue
break
return ASTDeclSpecsSimple(storage, threadLocal, inline, virtual,
explicit, constexpr, volatile, const,
friend, attrs)
explicitSpec, consteval, constexpr, constinit,
volatile, const, friend, attrs)

def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs:
if outer:
Expand Down
21 changes: 11 additions & 10 deletions sphinx/util/cfamily.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
)
[a-zA-Z0-9_]*\b
''')
integer_literal_re = re.compile(r'[1-9][0-9]*')
octal_literal_re = re.compile(r'0[0-7]*')
hex_literal_re = re.compile(r'0[xX][0-9a-fA-F][0-9a-fA-F]*')
binary_literal_re = re.compile(r'0[bB][01][01]*')
integer_literal_re = re.compile(r'[1-9][0-9]*(\'[0-9]+)*')
octal_literal_re = re.compile(r'0[0-7]*(\'[0-7]+)*')
hex_literal_re = re.compile(r'0[xX][0-9a-fA-F]+(\'[0-9a-fA-F]+)*')
binary_literal_re = re.compile(r'0[bB][01]+(\'[01]+)*')
integers_literal_suffix_re = re.compile(r'''(?x)
# unsigned and/or (long) long, in any order, but at least one of them
(
Expand All @@ -50,13 +50,14 @@
float_literal_re = re.compile(r'''(?x)
[+-]?(
# decimal
([0-9]+[eE][+-]?[0-9]+)
| ([0-9]*\.[0-9]+([eE][+-]?[0-9]+)?)
| ([0-9]+\.([eE][+-]?[0-9]+)?)
([0-9]+(\'[0-9]+)*[eE][+-]?[0-9]+(\'[0-9]+)*)
| (([0-9]+(\'[0-9]+)*)?\.[0-9]+(\'[0-9]+)*([eE][+-]?[0-9]+(\'[0-9]+)*)?)
| ([0-9]+(\'[0-9]+)*\.([eE][+-]?[0-9]+(\'[0-9]+)*)?)
# hex
| (0[xX][0-9a-fA-F]+[pP][+-]?[0-9a-fA-F]+)
| (0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+([pP][+-]?[0-9a-fA-F]+)?)
| (0[xX][0-9a-fA-F]+\.([pP][+-]?[0-9a-fA-F]+)?)
| (0[xX][0-9a-fA-F]+(\'[0-9a-fA-F]+)*[pP][+-]?[0-9a-fA-F]+(\'[0-9a-fA-F]+)*)
| (0[xX]([0-9a-fA-F]+(\'[0-9a-fA-F]+)*)?\.
[0-9a-fA-F]+(\'[0-9a-fA-F]+)*([pP][+-]?[0-9a-fA-F]+(\'[0-9a-fA-F]+)*)?)
| (0[xX][0-9a-fA-F]+(\'[0-9a-fA-F]+)*\.([pP][+-]?[0-9a-fA-F]+(\'[0-9a-fA-F]+)*)?)
)
''')
float_literal_suffix_re = re.compile(r'[fFlL]\b')
Expand Down

0 comments on commit eda4b1c

Please sign in to comment.