From 57237dbb075e112aab7685fc04179156b6cfa06a Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 24 Jun 2021 19:15:54 +0200 Subject: [PATCH 1/6] C++, support inline variables --- CHANGES | 1 + sphinx/domains/cpp.py | 9 +++++---- tests/test_domain_cpp.py | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index a0f1bab26..98a18a0fa 100644 --- a/CHANGES +++ b/CHANGES @@ -53,6 +53,7 @@ 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. Bugs fixed diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 14d8cde1b..b51cbd7e1 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -5957,12 +5957,13 @@ class DefinitionParser(BaseParser): if threadLocal: continue + if not inline and outer in ('function', 'member'): + inline = self.skip_word('inline') + if inline: + continue + if outer == 'function': # function-specifiers - if not inline: - inline = self.skip_word('inline') - if inline: - continue if not friend: friend = self.skip_word('friend') if friend: diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index a34fec172..9bf6da4f8 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -435,6 +435,8 @@ def test_domain_cpp_ast_member_definitions(): # check('member', 'int b : (true ? 8 : a) = 42', {1: 'b__i', 2: '1b'}) check('member', 'int b : 1 || new int{0}', {1: 'b__i', 2: '1b'}) + check('member', 'inline int n', {1: 'n__i', 2: '1n'}) + def test_domain_cpp_ast_function_definitions(): check('function', 'void f(volatile int)', {1: "f__iV", 2: "1fVi"}) From b94a60dc8941eb005844bb8789d68695f805973b Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 24 Jun 2021 19:39:15 +0200 Subject: [PATCH 2/6] C++, support consteval and constinit --- CHANGES | 6 +++- sphinx/domains/cpp.py | 70 ++++++++++++++++++++++++++-------------- tests/test_domain_cpp.py | 2 ++ 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/CHANGES b/CHANGES index 98a18a0fa..c862f0cb6 100644 --- a/CHANGES +++ b/CHANGES @@ -53,7 +53,11 @@ 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. +* C++, add support for + + - ``inline`` variables, + - ``consteval`` functions, + - ``constinit`` variables. Bugs fixed diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index b51cbd7e1..3e5aabc49 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -320,7 +320,8 @@ _fold_operator_re = re.compile(r'''(?x) _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', + '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', @@ -2101,14 +2102,17 @@ class ASTParametersQualifiers(ASTBase): 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: + explicit: bool, 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.consteval = consteval self.constexpr = constexpr + self.constinit = constinit self.volatile = volatile self.const = const self.friend = friend @@ -2122,7 +2126,9 @@ class ASTDeclSpecsSimple(ASTBase): self.inline or other.inline, self.virtual or other.virtual, self.explicit or other.explicit, + 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, @@ -2143,8 +2149,12 @@ class ASTDeclSpecsSimple(ASTBase): res.append('virtual') if self.explicit: res.append('explicit') + 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: @@ -2177,8 +2187,12 @@ class ASTDeclSpecsSimple(ASTBase): addSpace = _add(signode, 'virtual') if self.explicit: addSpace = _add(signode, 'explicit') + 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: @@ -5930,13 +5944,23 @@ class DefinitionParser(BaseParser): inline = None virtual = None explicit = 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'): @@ -5952,18 +5976,29 @@ class DefinitionParser(BaseParser): if self.skip_word('register'): storage = 'register' continue - if not threadLocal and outer == 'member': - threadLocal = self.skip_word('thread_local') - if threadLocal: - continue - 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 consteval: + consteval = self.skip_word('consteval') + if consteval: + continue if not friend: friend = self.skip_word('friend') if friend: @@ -5976,27 +6011,14 @@ class DefinitionParser(BaseParser): explicit = self.skip_word('explicit') if explicit: 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) + explicit, consteval, constexpr, constinit, + volatile, const, friend, attrs) def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs: if outer: diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 9bf6da4f8..47e5bf379 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -436,6 +436,7 @@ def test_domain_cpp_ast_member_definitions(): check('member', 'int b : 1 || new int{0}', {1: 'b__i', 2: '1b'}) check('member', 'inline int n', {1: 'n__i', 2: '1n'}) + check('member', 'constinit int n', {1: 'n__i', 2: '1n'}) def test_domain_cpp_ast_function_definitions(): @@ -567,6 +568,7 @@ def test_domain_cpp_ast_function_definitions(): check("function", "void f(int *volatile const p)", {1: "f__iPVC", 2: "1fPVCi"}) check('function', 'extern int f()', {1: 'f', 2: '1fv'}) + check('function', 'consteval int f()', {1: 'f', 2: '1fv'}) check('function', 'decltype(auto) f()', {1: 'f', 2: "1fv"}) From d5da6fdf50a2487287854bc01f575ce6e84a1903 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 24 Jun 2021 19:45:44 +0200 Subject: [PATCH 3/6] C++, support char8_t --- CHANGES | 3 ++- sphinx/domains/cpp.py | 9 +++++---- tests/test_domain_cpp.py | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index c862f0cb6..8b3290518 100644 --- a/CHANGES +++ b/CHANGES @@ -57,7 +57,8 @@ Features added - ``inline`` variables, - ``consteval`` functions, - - ``constinit`` variables. + - ``constinit`` variables, + - ``char8_t``. Bugs fixed diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 3e5aabc49..86c9e6918 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -319,8 +319,8 @@ _fold_operator_re = re.compile(r'''(?x) # 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', 'consteval', 'constexpr', 'constinit', + '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', @@ -427,6 +427,7 @@ _id_fundamental_v2 = { 'wchar_t': 'w', 'char32_t': 'Di', 'char16_t': 'Ds', + 'char8_t': 'Du', 'short': 's', 'short int': 's', 'signed short': 's', @@ -4956,8 +4957,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') diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 47e5bf379..1060cc26a 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -126,6 +126,7 @@ def test_domain_cpp_ast_fundamental_types(): id = t.replace(" ", "-").replace("long", "l").replace("int", "i") id = id.replace("bool", "b").replace("char", "c") id = id.replace("wc_t", "wchar_t").replace("c16_t", "char16_t") + id = id.replace("c8_t", "char8_t") id = id.replace("c32_t", "char32_t") return "f__%s" % id From 799c53aa119b94b2f11af2743c87f6cc3bee47e1 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 24 Jun 2021 20:26:22 +0200 Subject: [PATCH 4/6] C++, support explicit() specifier --- CHANGES | 3 +- sphinx/domains/cpp.py | 64 +++++++++++++++++++++++++++++++--------- tests/test_domain_cpp.py | 2 ++ 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index 8b3290518..aafc2d3da 100644 --- a/CHANGES +++ b/CHANGES @@ -58,7 +58,8 @@ Features added - ``inline`` variables, - ``consteval`` functions, - ``constinit`` variables, - - ``char8_t``. + - ``char8_t``, + - ``explicit()`` specifier. Bugs fixed diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 86c9e6918..854c8f988 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -2101,16 +2101,38 @@ class ASTParametersQualifiers(ASTBase): 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, consteval: bool, constexpr: bool, constinit: bool, + 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 @@ -2126,7 +2148,7 @@ class ASTDeclSpecsSimple(ASTBase): 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, @@ -2148,8 +2170,8 @@ class ASTDeclSpecsSimple(ASTBase): 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: @@ -2162,7 +2184,8 @@ class ASTDeclSpecsSimple(ASTBase): 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: @@ -2186,8 +2209,11 @@ class ASTDeclSpecsSimple(ASTBase): 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: @@ -2250,7 +2276,7 @@ class ASTDeclSpecs(ASTBase): 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: @@ -2264,7 +2290,7 @@ class ASTDeclSpecs(ASTBase): 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 @@ -5944,7 +5970,7 @@ class DefinitionParser(BaseParser): threadLocal = None inline = None virtual = None - explicit = None + explicitSpec = None consteval = None constexpr = None constinit = None @@ -6008,9 +6034,19 @@ class DefinitionParser(BaseParser): 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 attr = self._parse_attribute() if attr: @@ -6018,7 +6054,7 @@ class DefinitionParser(BaseParser): continue break return ASTDeclSpecsSimple(storage, threadLocal, inline, virtual, - explicit, consteval, constexpr, constinit, + explicitSpec, consteval, constexpr, constinit, volatile, const, friend, attrs) def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs: diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 1060cc26a..a4990e71f 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -571,6 +571,8 @@ def test_domain_cpp_ast_function_definitions(): check('function', 'extern int f()', {1: 'f', 2: '1fv'}) check('function', 'consteval int f()', {1: 'f', 2: '1fv'}) + check('function', 'explicit(true) void f()', {1: 'f', 2: '1fv'}) + check('function', 'decltype(auto) f()', {1: 'f', 2: "1fv"}) # TODO: make tests for functions in a template, e.g., Test From 7bc2e052c54694fea8c257516d90d80db9672322 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 24 Jun 2021 21:12:26 +0200 Subject: [PATCH 5/6] C++, C, support digit separators in literals --- CHANGES | 5 ++++- sphinx/util/cfamily.py | 21 +++++++++++---------- tests/test_domain_c.py | 11 ++++++++--- tests/test_domain_cpp.py | 11 ++++++++--- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/CHANGES b/CHANGES index aafc2d3da..61d9b4945 100644 --- a/CHANGES +++ b/CHANGES @@ -59,7 +59,10 @@ Features added - ``consteval`` functions, - ``constinit`` variables, - ``char8_t``, - - ``explicit()`` specifier. + - ``explicit()`` specifier, + - digit separators in literals. + +* C, add support for digit separators in literals. Bugs fixed diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index 2be2e390f..8d0896624 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -33,10 +33,10 @@ identifier_re = re.compile(r'''(?x) ) [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 ( @@ -50,13 +50,14 @@ integers_literal_suffix_re = re.compile(r'''(?x) 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') diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index d57738ec4..575b65362 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -155,7 +155,8 @@ def test_domain_c_ast_expressions(): # primary exprCheck('true') exprCheck('false') - ints = ['5', '0', '075', '0x0123456789ABCDEF', '0XF', '0b1', '0B1'] + ints = ['5', '0', '075', '0x0123456789ABCDEF', '0XF', '0b1', '0B1', + "0b0'1'0", "00'1'2", "0x0'1'2", "1'2'3"] unsignedSuffix = ['', 'u', 'U'] longSuffix = ['', 'l', 'L', 'll', 'LL'] for i in ints: @@ -170,14 +171,18 @@ def test_domain_c_ast_expressions(): '5e42', '5e+42', '5e-42', '5.', '5.e42', '5.e+42', '5.e-42', '.5', '.5e42', '.5e+42', '.5e-42', - '5.0', '5.0e42', '5.0e+42', '5.0e-42']: + '5.0', '5.0e42', '5.0e+42', '5.0e-42', + "1'2'3e7'8'9", "1'2'3.e7'8'9", + ".4'5'6e7'8'9", "1'2'3.4'5'6e7'8'9"]: expr = e + suffix exprCheck(expr) for e in [ 'ApF', 'Ap+F', 'Ap-F', 'A.', 'A.pF', 'A.p+F', 'A.p-F', '.A', '.ApF', '.Ap+F', '.Ap-F', - 'A.B', 'A.BpF', 'A.Bp+F', 'A.Bp-F']: + 'A.B', 'A.BpF', 'A.Bp+F', 'A.Bp-F', + "A'B'Cp1'2'3", "A'B'C.p1'2'3", + ".D'E'Fp1'2'3", "A'B'C.D'E'Fp1'2'3"]: expr = "0x" + e + suffix exprCheck(expr) exprCheck('"abc\\"cba"') # string diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index a4990e71f..cf2774af4 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -174,7 +174,8 @@ def test_domain_cpp_ast_expressions(): exprCheck('nullptr', 'LDnE') exprCheck('true', 'L1E') exprCheck('false', 'L0E') - ints = ['5', '0', '075', '0x0123456789ABCDEF', '0XF', '0b1', '0B1'] + ints = ['5', '0', '075', '0x0123456789ABCDEF', '0XF', '0b1', '0B1', + "0b0'1'0", "00'1'2", "0x0'1'2", "1'2'3"] unsignedSuffix = ['', 'u', 'U'] longSuffix = ['', 'l', 'L', 'll', 'LL'] for i in ints: @@ -187,11 +188,15 @@ def test_domain_cpp_ast_expressions(): decimalFloats = ['5e42', '5e+42', '5e-42', '5.', '5.e42', '5.e+42', '5.e-42', '.5', '.5e42', '.5e+42', '.5e-42', - '5.0', '5.0e42', '5.0e+42', '5.0e-42'] + '5.0', '5.0e42', '5.0e+42', '5.0e-42', + "1'2'3e7'8'9", "1'2'3.e7'8'9", + ".4'5'6e7'8'9", "1'2'3.4'5'6e7'8'9"] hexFloats = ['ApF', 'Ap+F', 'Ap-F', 'A.', 'A.pF', 'A.p+F', 'A.p-F', '.A', '.ApF', '.Ap+F', '.Ap-F', - 'A.B', 'A.BpF', 'A.Bp+F', 'A.Bp-F'] + 'A.B', 'A.BpF', 'A.Bp+F', 'A.Bp-F', + "A'B'Cp1'2'3", "A'B'C.p1'2'3", + ".D'E'Fp1'2'3", "A'B'C.D'E'Fp1'2'3"] for suffix in ['', 'f', 'F', 'l', 'L']: for e in decimalFloats: expr = e + suffix From 450d5caa373b8c2b65c16482989d94c744b6cc8d Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 24 Jun 2021 22:32:23 +0200 Subject: [PATCH 6/6] C++, support constrains in placeholders --- CHANGES | 4 +++- sphinx/domains/cpp.py | 32 ++++++++++++++++++++++++++++++-- tests/test_domain_cpp.py | 9 +++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 61d9b4945..432e114a0 100644 --- a/CHANGES +++ b/CHANGES @@ -60,7 +60,9 @@ Features added - ``constinit`` variables, - ``char8_t``, - ``explicit()`` specifier, - - digit separators in literals. + - 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. diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 854c8f988..c94f1d06d 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1882,9 +1882,11 @@ class ASTTrailingTypeSpecDecltype(ASTTrailingTypeSpec): 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: @@ -1899,6 +1901,9 @@ class ASTTrailingTypeSpecName(ASTTrailingTypeSpec): 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, @@ -1907,6 +1912,17 @@ class ASTTrailingTypeSpecName(ASTTrailingTypeSpec): 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): @@ -5856,7 +5872,19 @@ class DefinitionParser(BaseParser): 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': diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index cf2774af4..1ad216e5a 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -866,6 +866,15 @@ def test_domain_cpp_ast_templates(): check('type', 'template {key}A', {2: 'I_1CE1A'}, key='using') +def test_domain_cpp_ast_placeholder_types(): + check('function', 'void f(Sortable auto &v)', {1: 'f__SortableR', 2: '1fR8Sortable'}) + check('function', 'void f(const Sortable auto &v)', {1: 'f__SortableCR', 2: '1fRK8Sortable'}) + check('function', 'void f(Sortable decltype(auto) &v)', {1: 'f__SortableR', 2: '1fR8Sortable'}) + check('function', 'void f(const Sortable decltype(auto) &v)', {1: 'f__SortableCR', 2: '1fRK8Sortable'}) + check('function', 'void f(Sortable decltype ( auto ) &v)', {1: 'f__SortableR', 2: '1fR8Sortable'}, + output='void f(Sortable decltype(auto) &v)') + + def test_domain_cpp_ast_requires_clauses(): check('function', 'template requires A auto f() -> void requires B', {4: 'I0EIQaa1A1BE1fvv'})