Merge pull request #7376 from jakobandersen/c_cpp_error_messages

C, C++, improve error messages
This commit is contained in:
Jakob Lykke Andersen 2020-03-24 21:27:00 +01:00 committed by GitHub
commit 6deb592a2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 18 deletions

View File

@ -1986,6 +1986,10 @@ class DefinitionParser(BaseParser):
_prefix_keys = ('struct', 'enum', 'union') _prefix_keys = ('struct', 'enum', 'union')
@property
def language(self) -> str:
return 'C'
def _parse_string(self) -> str: def _parse_string(self) -> str:
if self.current_char != '"': if self.current_char != '"':
return None return None
@ -2697,7 +2701,7 @@ class DefinitionParser(BaseParser):
restrict=restrict, volatile=volatile, const=const, restrict=restrict, volatile=volatile, const=const,
attrs=attrs) attrs=attrs)
if typed and self.current_char == '(': # note: peeking, not skipping if typed and self.current_char == '(': # note: peeking, not skipping
# maybe this is the beginning of params,try that first, # maybe this is the beginning of params, try that first,
# otherwise assume it's noptr->declarator > ( ptr-declarator ) # otherwise assume it's noptr->declarator > ( ptr-declarator )
pos = self.pos pos = self.pos
try: try:
@ -2706,7 +2710,10 @@ class DefinitionParser(BaseParser):
typed) typed)
return res return res
except DefinitionError as exParamQual: except DefinitionError as exParamQual:
prevErrors.append((exParamQual, "If declId and parameters")) msg = "If declarator-id with parameters"
if paramMode == 'function':
msg += " (e.g., 'void f(int arg)')"
prevErrors.append((exParamQual, msg))
self.pos = pos self.pos = pos
try: try:
assert self.current_char == '(' assert self.current_char == '('
@ -2723,7 +2730,10 @@ class DefinitionParser(BaseParser):
return ASTDeclaratorParen(inner=inner, next=next) return ASTDeclaratorParen(inner=inner, next=next)
except DefinitionError as exNoPtrParen: except DefinitionError as exNoPtrParen:
self.pos = pos self.pos = pos
prevErrors.append((exNoPtrParen, "If parenthesis in noptr-declarator")) msg = "If parenthesis in noptr-declarator"
if paramMode == 'function':
msg += " (e.g., 'void (*f(int arg))(double)')"
prevErrors.append((exNoPtrParen, msg))
header = "Error in declarator" header = "Error in declarator"
raise self._make_multi_error(prevErrors, header) raise self._make_multi_error(prevErrors, header)
pos = self.pos pos = self.pos

View File

@ -4576,6 +4576,10 @@ class DefinitionParser(BaseParser):
super().__init__(definition, location=location) super().__init__(definition, location=location)
self.config = config self.config = config
@property
def language(self) -> str:
return 'C++'
def _parse_string(self) -> str: def _parse_string(self) -> str:
if self.current_char != '"': if self.current_char != '"':
return None return None
@ -5470,7 +5474,7 @@ class DefinitionParser(BaseParser):
self.skip_ws() self.skip_ws()
if not self.skip_string('('): if not self.skip_string('('):
if paramMode == 'function': if paramMode == 'function':
self.fail('Expecting "(" in parameters_and_qualifiers.') self.fail('Expecting "(" in parameters-and-qualifiers.')
else: else:
return None return None
args = [] args = []
@ -5483,7 +5487,7 @@ class DefinitionParser(BaseParser):
self.skip_ws() self.skip_ws()
if not self.skip_string(')'): if not self.skip_string(')'):
self.fail('Expected ")" after "..." in ' self.fail('Expected ")" after "..." in '
'parameters_and_qualifiers.') 'parameters-and-qualifiers.')
break break
# note: it seems that function arguments can always be named, # note: it seems that function arguments can always be named,
# even in function pointers and similar. # even in function pointers and similar.
@ -5498,7 +5502,7 @@ class DefinitionParser(BaseParser):
break break
else: else:
self.fail( self.fail(
'Expecting "," or ")" in parameters_and_qualifiers, ' 'Expecting "," or ")" in parameters-and-qualifiers, '
'got "%s".' % self.current_char) 'got "%s".' % self.current_char)
# TODO: why did we have this bail-out? # TODO: why did we have this bail-out?
@ -5529,7 +5533,7 @@ class DefinitionParser(BaseParser):
exceptionSpec = 'noexcept' exceptionSpec = 'noexcept'
self.skip_ws() self.skip_ws()
if self.skip_string('('): if self.skip_string('('):
self.fail('Parameterised "noexcept" not implemented.') self.fail('Parameterised "noexcept" not yet implemented.')
self.skip_ws() self.skip_ws()
override = self.skip_word_and_ws('override') override = self.skip_word_and_ws('override')
@ -5795,14 +5799,15 @@ class DefinitionParser(BaseParser):
typed) typed)
return res return res
except DefinitionError as exParamQual: except DefinitionError as exParamQual:
prevErrors.append((exParamQual, "If declId, parameters, and qualifiers")) prevErrors.append((exParamQual,
"If declarator-id with parameters-and-qualifiers"))
self.pos = pos self.pos = pos
try: try:
assert self.current_char == '(' assert self.current_char == '('
self.skip_string('(') self.skip_string('(')
# TODO: hmm, if there is a name, it must be in inner, right? # TODO: hmm, if there is a name, it must be in inner, right?
# TODO: hmm, if there must be parameters, they must b # TODO: hmm, if there must be parameters, they must be
# inside, right? # inside, right?
inner = self._parse_declarator(named, paramMode, typed) inner = self._parse_declarator(named, paramMode, typed)
if not self.skip_string(')'): if not self.skip_string(')'):
self.fail("Expected ')' in \"( ptr-declarator )\"") self.fail("Expected ')' in \"( ptr-declarator )\"")
@ -5821,7 +5826,7 @@ class DefinitionParser(BaseParser):
except DefinitionError as e: except DefinitionError as e:
self.pos = pos self.pos = pos
prevErrors.append((e, "If declarator-id")) prevErrors.append((e, "If declarator-id"))
header = "Error in declarator or parameters and qualifiers" header = "Error in declarator or parameters-and-qualifiers"
raise self._make_multi_error(prevErrors, header) raise self._make_multi_error(prevErrors, header)
def _parse_initializer(self, outer: str = None, allowFallback: bool = True def _parse_initializer(self, outer: str = None, allowFallback: bool = True
@ -5994,10 +5999,10 @@ class DefinitionParser(BaseParser):
if eExpr is None: if eExpr is None:
raise eType raise eType
errs = [] errs = []
errs.append((eExpr, "If default is an expression")) errs.append((eExpr, "If default template argument is an expression"))
errs.append((eType, "If default is a type")) errs.append((eType, "If default template argument is a type"))
msg = "Error in non-type template parameter" msg = "Error in non-type template parameter"
msg += " or constrianted template paramter." msg += " or constrained template parameter."
raise self._make_multi_error(errs, msg) raise self._make_multi_error(errs, msg)
def _parse_type_using(self) -> ASTTypeUsing: def _parse_type_using(self) -> ASTTypeUsing:

View File

@ -154,19 +154,23 @@ class BaseParser:
result = [header, '\n'] result = [header, '\n']
for e in errors: for e in errors:
if len(e[1]) > 0: if len(e[1]) > 0:
ident = ' ' indent = ' '
result.append(e[1]) result.append(e[1])
result.append(':\n') result.append(':\n')
for line in str(e[0]).split('\n'): for line in str(e[0]).split('\n'):
if len(line) == 0: if len(line) == 0:
continue continue
result.append(ident) result.append(indent)
result.append(line) result.append(line)
result.append('\n') result.append('\n')
else: else:
result.append(str(e[0])) result.append(str(e[0]))
return DefinitionError(''.join(result)) return DefinitionError(''.join(result))
@property
def language(self) -> str:
raise NotImplementedError
def status(self, msg: str) -> None: def status(self, msg: str) -> None:
# for debugging # for debugging
indicator = '-' * self.pos + '^' indicator = '-' * self.pos + '^'
@ -176,8 +180,8 @@ class BaseParser:
errors = [] errors = []
indicator = '-' * self.pos + '^' indicator = '-' * self.pos + '^'
exMain = DefinitionError( exMain = DefinitionError(
'Invalid definition: %s [error at %d]\n %s\n %s' % 'Invalid %s declaration: %s [error at %d]\n %s\n %s' %
(msg, self.pos, self.definition, indicator)) (self.language, msg, self.pos, self.definition, indicator))
errors.append((exMain, "Main error")) errors.append((exMain, "Main error"))
for err in self.otherErrors: for err in self.otherErrors:
errors.append((err, "Potential other error")) errors.append((err, "Potential other error"))