Fix a crash on invalid found by fuzzing. (#3404)

When a `namespace` keyword has no `;` following it, we recover by
building a parse tree `Namespace` node from the `Namespace` token (as
there isn't a `;` token). Allow this correspondence on errors.

Also teach the diagnostics in this case to avoid the end-of-file token
as that's almost always going to be a less meaningful location. Instead,
we can point at the introducer which should at least be in the code that
led to the error.
This commit is contained in:
Chandler Carruth
2023-11-16 18:26:39 +00:00
committed by GitHub
parent 204c04dbb9
commit d3eae6d1f0
3 changed files with 69 additions and 2 deletions
@@ -27,7 +27,13 @@ static auto HandleDeclNameAndParams(Context& context, State after_name)
CARBON_DIAGNOSTIC(ExpectedDeclName, Error,
"`{0}` introducer should be followed by a name.",
Lex::TokenKind);
context.emitter().Emit(*context.position(), ExpectedDeclName,
Lex::Token location = *context.position();
if (context.tokens().GetKind(location) == Lex::TokenKind::EndOfFile) {
// The end of file is often an especially unhelpful location. If that's
// the best we can do here, back up the location to the introducer itself.
location = state.token;
}
context.emitter().Emit(location, ExpectedDeclName,
context.tokens().GetKind(state.token));
context.ReturnErrorOnState();
context.AddLeafNode(NodeKind::InvalidParse, *context.position(),
+3 -1
View File
@@ -141,7 +141,9 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibrarySpecifier, 1, CARBON_TOKEN(Library))
// _external_: Name or QualifiedDecl
// Namespace
CARBON_PARSE_NODE_KIND_CHILD_COUNT(NamespaceStart, 0, CARBON_TOKEN(Namespace))
CARBON_PARSE_NODE_KIND_CHILD_COUNT(Namespace, 2, CARBON_TOKEN(Semi))
CARBON_PARSE_NODE_KIND_CHILD_COUNT(Namespace, 2,
CARBON_TOKEN(Semi)
CARBON_IF_ERROR(CARBON_TOKEN(Namespace)))
// A code block:
// CodeBlockStart
@@ -0,0 +1,59 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:11: ERROR: `namespace` introducer should be followed by a name.
// CHECK:STDERR: namespace 123
// CHECK:STDERR: ^
namespace 123
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:11: ERROR: `namespace` introducer should be followed by a name.
// CHECK:STDERR: namespace ""
// CHECK:STDERR: ^
namespace ""
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:11: ERROR: `namespace` introducer should be followed by a name.
// CHECK:STDERR: namespace +
// CHECK:STDERR: ^
namespace +
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:11: ERROR: `namespace` introducer should be followed by a name.
// CHECK:STDERR: namespace bool
// CHECK:STDERR: ^
namespace bool
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:11: ERROR: `namespace` introducer should be followed by a name.
// CHECK:STDERR: namespace namespace namespace namespace namespace
// CHECK:STDERR: ^
namespace namespace namespace namespace namespace
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+3]]:1: ERROR: `namespace` introducer should be followed by a name.
// CHECK:STDERR: namespace
// CHECK:STDERR: ^
namespace
// CHECK:STDOUT: - filename: fail_incomplete.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: '123', has_error: yes},
// CHECK:STDOUT: {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: '""', has_error: yes},
// CHECK:STDOUT: {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: '+', has_error: yes},
// CHECK:STDOUT: {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: 'bool', has_error: yes},
// CHECK:STDOUT: {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: 'namespace', has_error: yes},
// CHECK:STDOUT: {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: '', has_error: yes},
// CHECK:STDOUT: {kind: 'Namespace', text: 'namespace', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]