summaryrefslogtreecommitdiff
path: root/sphinx/domains/cpp.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/domains/cpp.py')
-rw-r--r--sphinx/domains/cpp.py373
1 files changed, 209 insertions, 164 deletions
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 0ed987384..39955d4f4 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -5,7 +5,7 @@
The C++ language domain.
- :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
+ :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@@ -1285,7 +1285,7 @@ class ASTTemplateParamType(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
- return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
@property
def isPack(self):
@@ -1314,6 +1314,44 @@ class ASTTemplateParamType(ASTBase):
self.data.describe_signature(signode, mode, env, symbol)
+class ASTTemplateParamConstrainedTypeWithInit(ASTBase):
+ def __init__(self, type, init):
+ # type: (Any, Any) -> None
+ assert type
+ self.type = type
+ self.init = init
+
+ @property
+ def name(self):
+ # type: () -> ASTNestedName
+ return self.type.name
+
+ def get_id(self, version, objectType=None, symbol=None):
+ # type: (int, unicode, Symbol) -> unicode
+ # this is not part of the normal name mangling in C++
+ assert version >= 2
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id(version, prefixed=False)
+ else:
+ return self.type.get_id(version)
+
+ def __unicode__(self):
+ # type: () -> unicode
+ res = text_type(self.type)
+ if self.init:
+ res += " = "
+ res += text_type(self.init)
+ return res
+
+ def describe_signature(self, signode, mode, env, symbol):
+ # type: (addnodes.desc_signature, unicode, BuildEnvironment, Symbol) -> None
+ self.type.describe_signature(signode, mode, env, symbol)
+ if self.init:
+ signode += nodes.Text(" = ")
+ self.init.describe_signature(signode, mode, env, symbol)
+
+
class ASTTemplateParamTemplateType(ASTBase):
def __init__(self, nestedParams, data):
# type: (Any, Any) -> None
@@ -1326,7 +1364,7 @@ class ASTTemplateParamTemplateType(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
- return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
def get_identifier(self):
# type: () -> unicode
@@ -1363,16 +1401,16 @@ class ASTTemplateParamNonType(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
- return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
def get_identifier(self):
# type: () -> unicode
name = self.param.name
if name:
assert len(name.names) == 1
- assert name.names[0].identifier
+ assert name.names[0].identOrOp
assert not name.names[0].templateArgs
- return name.names[0].identifier
+ return name.names[0].identOrOp
else:
return None
@@ -1456,7 +1494,7 @@ class ASTTemplateIntroductionParameter(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
- return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
@property
def isPack(self):
@@ -1612,8 +1650,8 @@ class ASTOperatorBuildIn(ASTBase):
else:
return u'operator' + self.op
- def describe_signature(self, signode, mode, env, prefix, symbol):
- # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
+ def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol):
+ # type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None
_verify_description_mode(mode)
identifier = text_type(self)
if mode == 'lastIsName':
@@ -1646,8 +1684,8 @@ class ASTOperatorType(ASTBase):
# type: () -> unicode
return text_type(self)
- def describe_signature(self, signode, mode, env, prefix, symbol):
- # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
+ def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol):
+ # type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None
_verify_description_mode(mode)
identifier = text_type(self)
if mode == 'lastIsName':
@@ -1676,8 +1714,8 @@ class ASTOperatorLiteral(ASTBase):
# type: () -> unicode
return u'operator""' + text_type(self.identifier)
- def describe_signature(self, signode, mode, env, prefix, symbol):
- # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
+ def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol):
+ # type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None
_verify_description_mode(mode)
identifier = text_type(self)
if mode == 'lastIsName':
@@ -1750,9 +1788,9 @@ class ASTTemplateArgs(ASTBase):
class ASTNestedNameElement(ASTBase):
- def __init__(self, identifier, templateArgs):
+ def __init__(self, identOrOp, templateArgs):
# type: (Any, Any) -> None
- self.identifier = identifier
+ self.identOrOp = identOrOp
self.templateArgs = templateArgs
def is_operator(self):
@@ -1761,14 +1799,14 @@ class ASTNestedNameElement(ASTBase):
def get_id(self, version):
# type: (int) -> unicode
- res = self.identifier.get_id(version)
+ res = self.identOrOp.get_id(version)
if self.templateArgs:
res += self.templateArgs.get_id(version)
return res
def __unicode__(self):
# type: () -> unicode
- res = text_type(self.identifier)
+ res = text_type(self.identOrOp)
if self.templateArgs:
res += text_type(self.templateArgs)
return res
@@ -1776,16 +1814,18 @@ class ASTNestedNameElement(ASTBase):
def describe_signature(self, signode, mode, env, prefix, symbol):
# type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
tArgs = text_type(self.templateArgs) if self.templateArgs is not None else ''
- self.identifier.describe_signature(signode, mode, env, prefix, tArgs, symbol)
+ self.identOrOp.describe_signature(signode, mode, env, prefix, tArgs, symbol)
if self.templateArgs is not None:
self.templateArgs.describe_signature(signode, mode, env, symbol)
class ASTNestedName(ASTBase):
- def __init__(self, names, rooted):
- # type: (List[Any], bool) -> None
+ def __init__(self, names, templates, rooted):
+ # type: (List[Any], List[bool], bool) -> None
assert len(names) > 0
self.names = names
+ self.templates = templates
+ assert len(self.names) == len(self.templates)
self.rooted = rooted
@property
@@ -1826,8 +1866,13 @@ class ASTNestedName(ASTBase):
res = [] # type: List[unicode]
if self.rooted:
res.append('')
- for n in self.names:
- res.append(text_type(n))
+ for i in range(len(self.names)):
+ n = self.names[i]
+ t = self.templates[i]
+ if t:
+ res.append("template " + text_type(n))
+ else:
+ res.append(text_type(n))
return '::'.join(res)
def describe_signature(self, signode, mode, env, symbol):
@@ -1854,10 +1899,14 @@ class ASTNestedName(ASTBase):
prefix = '' # type: unicode
first = True
names = self.names[:-1] if mode == 'lastIsName' else self.names
- for name in names:
+ for i in range(len(names)):
+ name = names[i]
+ template = self.templates[i]
if not first:
signode += nodes.Text('::')
prefix += '::'
+ if template:
+ signode += nodes.Text("template ")
first = False
if name != '':
if (name.templateArgs and # type: ignore
@@ -1870,6 +1919,8 @@ class ASTNestedName(ASTBase):
if mode == 'lastIsName':
if len(self.names) > 1:
signode += addnodes.desc_addname('::', '::')
+ if self.templates[-1]:
+ signode += nodes.Text("template ")
self.names[-1].describe_signature(signode, mode, env, '', symbol)
else:
raise Exception('Unknown description mode: %s' % mode)
@@ -3259,23 +3310,20 @@ class Symbol(object):
# type: () -> None
if not self.parent:
# parent == None means global scope, so declaration means a parent
- assert not self.identifier
+ assert not self.identOrOp
assert not self.templateParams
assert not self.templateArgs
assert not self.declaration
assert not self.docname
else:
- if not self.identifier:
- # in case it's an operator
- assert self.declaration
if self.declaration:
assert self.docname
- def __init__(self, parent, identifier,
+ def __init__(self, parent, identOrOp,
templateParams, templateArgs, declaration, docname):
# type: (Any, Any, Any, Any, Any, unicode) -> None
self.parent = parent
- self.identifier = identifier
+ self.identOrOp = identOrOp
self.templateParams = templateParams # template<templateParams>
self.templateArgs = templateArgs # identifier<templateArgs>
self.declaration = declaration
@@ -3300,7 +3348,7 @@ class Symbol(object):
else:
decl = None
nne = ASTNestedNameElement(p.get_identifier(), None)
- nn = ASTNestedName([nne], rooted=False)
+ nn = ASTNestedName([nne], [False], rooted=False)
self._add_symbols(nn, [], decl, docname)
# add symbols for function parameters, if any
if declaration is not None and declaration.function_params is not None:
@@ -3314,8 +3362,8 @@ class Symbol(object):
decl = ASTDeclaration('functionParam', None, None, p)
assert not nn.rooted
assert len(nn.names) == 1
- identifier = nn.names[0].identifier
- Symbol(parent=self, identifier=identifier,
+ identOrOp = nn.names[0].identOrOp
+ Symbol(parent=self, identOrOp=identOrOp,
templateParams=None, templateArgs=None,
declaration=decl, docname=docname)
@@ -3339,12 +3387,7 @@ class Symbol(object):
if sChild.declaration and sChild.docname == docname:
sChild.declaration = None
sChild.docname = None
- # Just remove operators, because there is no identification if
- # they got removed.
- # Don't remove other symbols because they may be used in namespace
- # directives.
- if sChild.identifier or sChild.declaration:
- newChildren.append(sChild)
+ newChildren.append(sChild)
self.children = newChildren
def get_all_symbols(self):
@@ -3364,26 +3407,22 @@ class Symbol(object):
symbols.reverse()
key = []
for s in symbols:
- if s.identifier:
- nne = ASTNestedNameElement(s.identifier, s.templateArgs)
- else:
- assert s.declaration
- nne = s.declaration.name.names[-1]
+ nne = ASTNestedNameElement(s.identOrOp, s.templateArgs)
key.append((nne, s.templateParams))
return key
def get_full_nested_name(self):
# type: () -> ASTNestedName
names = []
+ templates = []
for nne, templateParams in self.get_lookup_key():
names.append(nne)
- return ASTNestedName(names, rooted=False)
+ templates.append(False)
+ return ASTNestedName(names, templates, rooted=False)
- def _find_named_symbol(self, identifier, templateParams,
- templateArgs, operator,
+ def _find_named_symbol(self, identOrOp, templateParams, templateArgs,
templateShorthand, matchSelf):
- # type: (Any, Any, Any, Any, Any, bool) -> Symbol
- assert (identifier is None) != (operator is None)
+ # type: (Any, Any, Any, Any, bool) -> Symbol
def isSpecialization():
# the names of the template parameters must be given exactly as args
@@ -3411,17 +3450,8 @@ class Symbol(object):
templateArgs = None
def matches(s):
- if s.identifier != identifier:
+ if s.identOrOp != identOrOp:
return False
- if not s.identifier:
- if not s.declaration:
- return False
- assert operator
- name = s.declaration.name.names[-1]
- if not name.is_operator():
- return False
- if text_type(name) != text_type(operator):
- return False
if (s.templateParams is None) != (templateParams is None):
if templateParams is not None:
# we query with params, they must match params
@@ -3462,10 +3492,7 @@ class Symbol(object):
names = nestedName.names
iTemplateDecl = 0
for name in names[:-1]:
- # there shouldn't be anything inside an operator
- # (other than template parameters, which are not added this way, right?)
- assert not name.is_operator()
- identifier = name.identifier
+ identOrOp = name.identOrOp
templateArgs = name.templateArgs
if templateArgs:
assert iTemplateDecl < len(templateDecls)
@@ -3473,27 +3500,20 @@ class Symbol(object):
iTemplateDecl += 1
else:
templateParams = None
- symbol = parentSymbol._find_named_symbol(identifier,
+ symbol = parentSymbol._find_named_symbol(identOrOp,
templateParams,
templateArgs,
- operator=None,
templateShorthand=False,
matchSelf=False)
if symbol is None:
- symbol = Symbol(parent=parentSymbol, identifier=identifier,
+ symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs, declaration=None,
docname=None)
parentSymbol = symbol
name = names[-1]
- if name.is_operator():
- identifier = None
- templateArgs = None
- operator = name
- else:
- identifier = name.identifier
- templateArgs = name.templateArgs
- operator = None
+ identOrOp = name.identOrOp
+ templateArgs = name.templateArgs
if iTemplateDecl < len(templateDecls):
if iTemplateDecl + 1 != len(templateDecls):
print(text_type(templateDecls))
@@ -3503,10 +3523,9 @@ class Symbol(object):
else:
assert iTemplateDecl == len(templateDecls)
templateParams = None
- symbol = parentSymbol._find_named_symbol(identifier,
+ symbol = parentSymbol._find_named_symbol(identOrOp,
templateParams,
templateArgs,
- operator,
templateShorthand=False,
matchSelf=False)
if symbol:
@@ -3523,7 +3542,7 @@ class Symbol(object):
return symbol
# It may simply be a function overload, so let's compare ids.
isRedeclaration = True
- candSymbol = Symbol(parent=parentSymbol, identifier=identifier,
+ candSymbol = Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs,
declaration=declaration,
@@ -3543,7 +3562,7 @@ class Symbol(object):
candSymbol.isRedeclaration = True
raise _DuplicateSymbolError(symbol, declaration)
else:
- symbol = Symbol(parent=parentSymbol, identifier=identifier,
+ symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs,
declaration=declaration,
@@ -3554,22 +3573,9 @@ class Symbol(object):
# type: (Any, List[unicode], BuildEnvironment) -> None
assert other is not None
for otherChild in other.children:
- if not otherChild.identifier:
- if not otherChild.declaration:
- print("Problem in symbol tree merging")
- print("OtherChild.dump:")
- print(otherChild.dump(0))
- print("Other.dump:")
- print(other.dump(0))
- assert otherChild.declaration
- operator = otherChild.declaration.name.names[-1]
- assert operator.is_operator()
- else:
- operator = None
- ourChild = self._find_named_symbol(otherChild.identifier,
+ ourChild = self._find_named_symbol(otherChild.identOrOp,
otherChild.templateParams,
otherChild.templateArgs,
- operator,
templateShorthand=False,
matchSelf=False)
if ourChild is None:
@@ -3614,12 +3620,12 @@ class Symbol(object):
templateDecls = []
return self._add_symbols(nestedName, templateDecls, declaration, docname)
- def find_identifier(self, identifier, matchSelf):
+ def find_identifier(self, identOrOp, matchSelf):
# type: (Any, bool) -> Symbol
- if matchSelf and self.identifier and self.identifier == identifier:
+ if matchSelf and self.identOrOp == identOrOp:
return self
for s in self.children:
- if s.identifier and s.identifier == identifier:
+ if s.identOrOp == identOrOp:
return s
return None
@@ -3627,16 +3633,10 @@ class Symbol(object):
# type: (List[Tuple[Any, Any]]) -> Symbol
s = self
for name, templateParams in key:
- if name.is_operator():
- identifier = None
- templateArgs = None
- operator = name
- else:
- identifier = name.identifier
- templateArgs = name.templateArgs
- operator = None
- s = s._find_named_symbol(identifier, templateParams,
- templateArgs, operator,
+ identOrOp = name.identOrOp
+ templateArgs = name.templateArgs
+ s = s._find_named_symbol(identOrOp,
+ templateParams, templateArgs,
templateShorthand=False,
matchSelf=False)
if not s:
@@ -3660,13 +3660,13 @@ class Symbol(object):
firstName = names[0]
if not firstName.is_operator():
while parentSymbol.parent:
- if parentSymbol.find_identifier(firstName.identifier,
+ if parentSymbol.find_identifier(firstName.identOrOp,
matchSelf=matchSelf):
# if we are in the scope of a constructor but wants to reference the class
# we need to walk one extra up
if (len(names) == 1 and typ == 'class' and matchSelf and
- parentSymbol.parent and parentSymbol.parent.identifier and
- parentSymbol.parent.identifier == firstName.identifier):
+ parentSymbol.parent and
+ parentSymbol.parent.identOrOp == firstName.identOrOp):
pass
else:
break
@@ -3675,48 +3675,36 @@ class Symbol(object):
for iName in range(len(names)):
name = names[iName]
if iName + 1 == len(names):
- if name.is_operator():
- identifier = None
- templateArgs = None
- operator = name
- else:
- identifier = name.identifier
- templateArgs = name.templateArgs
- operator = None
+ identOrOp = name.identOrOp
+ templateArgs = name.templateArgs
if iTemplateDecl < len(templateDecls):
assert iTemplateDecl + 1 == len(templateDecls)
templateParams = templateDecls[iTemplateDecl]
else:
assert iTemplateDecl == len(templateDecls)
templateParams = None
- symbol = parentSymbol._find_named_symbol(identifier,
+ symbol = parentSymbol._find_named_symbol(identOrOp,
templateParams, templateArgs,
- operator,
templateShorthand=templateShorthand,
matchSelf=matchSelf)
if symbol is not None:
return symbol
# try without template params and args
- symbol = parentSymbol._find_named_symbol(identifier,
+ symbol = parentSymbol._find_named_symbol(identOrOp,
None, None,
- operator,
templateShorthand=templateShorthand,
matchSelf=matchSelf)
return symbol
else:
- # there shouldn't be anything inside an operator
- assert not name.is_operator()
- identifier = name.identifier
+ identOrOp = name.identOrOp
templateArgs = name.templateArgs
if templateArgs and iTemplateDecl < len(templateDecls):
templateParams = templateDecls[iTemplateDecl]
iTemplateDecl += 1
else:
templateParams = None
- symbol = parentSymbol._find_named_symbol(identifier,
- templateParams,
- templateArgs,
- operator=None,
+ symbol = parentSymbol._find_named_symbol(identOrOp,
+ templateParams, templateArgs,
templateShorthand=templateShorthand,
matchSelf=matchSelf)
if symbol is None:
@@ -3739,8 +3727,8 @@ class Symbol(object):
res.append(text_type(self.templateParams))
res.append('\n')
res.append('\t' * indent)
- if self.identifier:
- res.append(text_type(self.identifier))
+ if self.identOrOp:
+ res.append(text_type(self.identOrOp))
else:
res.append(text_type(self.declaration))
if self.templateArgs:
@@ -3781,6 +3769,8 @@ class DefinitionParser(object):
self.last_match = None # type: Match
self._previous_state = (0, None) # type: Tuple[int, Match]
self.otherErrors = [] # type: List[DefinitionError]
+ # in our tests the following is set to False to capture bad parsing
+ self.allowFallbackExpressionParsing = True
self.warnEnv = warnEnv
self.config = config
@@ -4121,6 +4111,13 @@ class DefinitionParser(object):
# TODO: hmm, would we need to try both with operatorCast and with None?
prefix = self._parse_type(False, 'operatorCast')
prefixType = 'typeOperatorCast'
+ # | simple-type-specifier "(" expression-list [opt] ")"
+ # | simple-type-specifier braced-init-list
+ # | typename-specifier "(" expression-list [opt] ")"
+ # | typename-specifier braced-init-list
+ self.skip_ws()
+ if self.current_char != '(' and self.current_char != '{':
+ self.fail("Expecting '(' or '{' after type in cast expression.")
except DefinitionError as eInner:
self.pos = pos
header = "Error in postfix expression, expected primary expression or type."
@@ -4361,7 +4358,7 @@ class DefinitionParser(object):
# TODO: actually parse the second production
return self._parse_assignment_expression(inTemplate=inTemplate)
- def _parse_expression_fallback(self, end, parser):
+ def _parse_expression_fallback(self, end, parser, allow=True):
# Stupidly "parse" an expression.
# 'end' should be a list of characters which ends the expression.
@@ -4370,6 +4367,10 @@ class DefinitionParser(object):
try:
return parser()
except DefinitionError as e:
+ # some places (e.g., template parameters) we really don't want to use fallback,
+ # and for testing we may want to globally disable it
+ if not allow or not self.allowFallbackExpressionParsing:
+ raise
self.warn("Parsing of expression failed. Using fallback parser."
" Error was:\n%s" % e.description)
self.pos = prevPos
@@ -4480,7 +4481,8 @@ class DefinitionParser(object):
def _parse_nested_name(self, memberPointer=False):
# type: (bool) -> ASTNestedName
- names = []
+ names = [] # type: List[Any]
+ templates = [] # type: List[bool]
self.skip_ws()
rooted = False
@@ -4488,14 +4490,17 @@ class DefinitionParser(object):
rooted = True
while 1:
self.skip_ws()
- if self.skip_word_and_ws('template'):
- self.fail("'template' in nested name not implemented.")
- elif self.skip_word_and_ws('operator'):
- op = self._parse_operator()
- names.append(op)
+ if len(names) > 0:
+ template = self.skip_word_and_ws('template')
+ else:
+ template = False
+ templates.append(template)
+ if self.skip_word_and_ws('operator'):
+ identOrOp = self._parse_operator()
else:
if not self.match(_identifier_re):
if memberPointer and len(names) > 0:
+ templates.pop()
break
self.fail("Expected identifier in nested name.")
identifier = self.matched_text
@@ -4503,24 +4508,24 @@ class DefinitionParser(object):
if identifier in _keywords:
self.fail("Expected identifier in nested name, "
"got keyword: %s" % identifier)
- # try greedily to get template parameters,
- # but otherwise a < might be because we are in an expression
- pos = self.pos
- try:
- templateArgs = self._parse_template_argument_list()
- except DefinitionError as ex:
- self.pos = pos
- templateArgs = None
- self.otherErrors.append(ex)
- identifier = ASTIdentifier(identifier) # type: ignore
- names.append(ASTNestedNameElement(identifier, templateArgs))
+ identOrOp = ASTIdentifier(identifier)
+ # try greedily to get template arguments,
+ # but otherwise a < might be because we are in an expression
+ pos = self.pos
+ try:
+ templateArgs = self._parse_template_argument_list()
+ except DefinitionError as ex:
+ self.pos = pos
+ templateArgs = None
+ self.otherErrors.append(ex)
+ names.append(ASTNestedNameElement(identOrOp, templateArgs))
self.skip_ws()
if not self.skip_string('::'):
if memberPointer:
self.fail("Expected '::' in pointer to member (function).")
break
- return ASTNestedName(names, rooted)
+ return ASTNestedName(names, templates, rooted)
def _parse_trailing_type_spec(self):
# type: () -> Any
@@ -4598,7 +4603,7 @@ class DefinitionParser(object):
self.fail('Expected ")" after "..." in '
'parameters_and_qualifiers.')
break
- # note: it seems that function arguments can always sbe named,
+ # note: it seems that function arguments can always be named,
# even in function pointers and similar.
arg = self._parse_type_with_init(outer=None, named='single')
# TODO: parse default parameters # TODO: didn't we just do that?
@@ -4785,7 +4790,7 @@ class DefinitionParser(object):
if self.match(_identifier_re):
identifier = ASTIdentifier(self.matched_text)
nne = ASTNestedNameElement(identifier, None)
- declId = ASTNestedName([nne], rooted=False)
+ declId = ASTNestedName([nne], [False], rooted=False)
# if it's a member pointer, we may have '::', which should be an error
self.skip_ws()
if self.current_char == ':':
@@ -4919,8 +4924,8 @@ class DefinitionParser(object):
header = "Error in declarator or parameters and qualifiers"
raise self._make_multi_error(prevErrors, header)
- def _parse_initializer(self, outer=None):
- # type: (unicode) -> ASTInitializer
+ def _parse_initializer(self, outer=None, allowFallback=True):
+ # type: (unicode, bool) -> ASTInitializer
self.skip_ws()
# TODO: support paren and brace initialization for memberObject
if not self.skip_string('='):
@@ -4929,15 +4934,18 @@ class DefinitionParser(object):
if outer == 'member':
def parser():
return self._parse_assignment_expression(inTemplate=False)
- value = self._parse_expression_fallback([], parser)
+ value = self._parse_expression_fallback([], parser,
+ allow=allowFallback)
elif outer == 'templateParam':
def parser():
return self._parse_assignment_expression(inTemplate=True)
- value = self._parse_expression_fallback([',', '>'], parser)
+ value = self._parse_expression_fallback([',', '>'], parser,
+ allow=allowFallback)
elif outer is None: # function parameter
def parser():
return self._parse_assignment_expression(inTemplate=False)
- value = self._parse_expression_fallback([',', ')'], parser)
+ value = self._parse_expression_fallback([',', ')'], parser,
+ allow=allowFallback)
else:
self.fail("Internal error, initializer for outer '%s' not "
"implemented." % outer)
@@ -5027,12 +5035,48 @@ class DefinitionParser(object):
return ASTType(declSpecs, decl)
def _parse_type_with_init(self, named, outer):
- # type: (Union[bool, unicode], unicode) -> ASTTypeWithInit
+ # type: (Union[bool, unicode], unicode) -> Any
if outer:
assert outer in ('type', 'member', 'function', 'templateParam')
type = self._parse_type(outer=outer, named=named)
- init = self._parse_initializer(outer=outer)
- return ASTTypeWithInit(type, init)
+ if outer != 'templateParam':
+ init = self._parse_initializer(outer=outer)
+ return ASTTypeWithInit(type, init)
+ # it could also be a constrained type parameter, e.g., C T = int&
+ pos = self.pos
+ eExpr = None
+ try:
+ init = self._parse_initializer(outer=outer, allowFallback=False)
+ # note: init may be None if there is no =
+ if init is None:
+ return ASTTypeWithInit(type, None)
+ # we parsed an expression, so we must have a , or a >,
+ # otherwise the expression didn't get everything
+ self.skip_ws()
+ if self.current_char != ',' and self.current_char != '>':
+ # pretend it didn't happen
+ self.pos = pos
+ init = None
+ else:
+ # we assume that it was indeed an expression
+ return ASTTypeWithInit(type, init)
+ except DefinitionError as e:
+ self.pos = pos
+ eExpr = e
+ if not self.skip_string("="):
+ return ASTTypeWithInit(type, None)
+ try:
+ typeInit = self._parse_type(named=False, outer=None)
+ return ASTTemplateParamConstrainedTypeWithInit(type, typeInit)
+ except DefinitionError as eType:
+ if eExpr is None:
+ raise eType
+ errs = []
+ errs.append((eExpr, "If default is an expression"))
+ errs.append((eType, "If default is a type"))
+ msg = "Error in non-type template parameter"
+ msg += " or constrianted template paramter."
+ raise self._make_multi_error(errs, msg)
def _parse_type_using(self):
# type: () -> ASTTypeUsing
@@ -5156,13 +5200,14 @@ class DefinitionParser(object):
param = ASTTemplateParamType(data)
templateParams.append(param)
else:
- # declare a non-type parameter
+ # declare a non-type parameter, or constrained type parameter
pos = self.pos
try:
param = self._parse_type_with_init('maybe', 'templateParam')
templateParams.append(ASTTemplateParamNonType(param))
except DefinitionError as e:
- prevErrors.append((e, "If non-type template parameter"))
+ msg = "If non-type template parameter or constrained template parameter"
+ prevErrors.append((e, msg))
self.pos = pos
self.skip_ws()
if self.skip_string('>'):
@@ -5386,7 +5431,7 @@ class DefinitionParser(object):
def _make_phony_error_name():
# type: () -> ASTNestedName
nne = ASTNestedNameElement(ASTIdentifier("PhonyNameDueToError"), None)
- return ASTNestedName([nne], rooted=False)
+ return ASTNestedName([nne], [False], rooted=False)
class CPPObject(ObjectDescription):
@@ -5421,7 +5466,7 @@ class CPPObject(ObjectDescription):
# then add the name to the parent scope
symbol = ast.symbol
assert symbol
- assert symbol.identifier is not None
+ assert symbol.identOrOp is not None
assert symbol.templateParams is None
assert symbol.templateArgs is None
parentSymbol = symbol.parent
@@ -5434,7 +5479,7 @@ class CPPObject(ObjectDescription):
if parentDecl is None:
# the parent is not explicitly declared
# TODO: we could warn, but it could be a style to just assume
- # enumerator parnets to be scoped
+ # enumerator parents to be scoped
return
if parentDecl.objectType != 'enum':
# TODO: maybe issue a warning, enumerators in non-enums is weird,
@@ -5444,13 +5489,13 @@ class CPPObject(ObjectDescription):
return
targetSymbol = parentSymbol.parent
- s = targetSymbol.find_identifier(symbol.identifier, matchSelf=False)
+ s = targetSymbol.find_identifier(symbol.identOrOp, matchSelf=False)
if s is not None:
# something is already declared with that name
return
declClone = symbol.declaration.clone()
declClone.enumeratorScopedSymbol = symbol
- Symbol(parent=targetSymbol, identifier=symbol.identifier,
+ Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp,
templateParams=None, templateArgs=None,
declaration=declClone,
docname=self.env.docname)