Prechádzať zdrojové kódy

Fix crash in character literal lexing (#6805)

When lexing a hash-prefixed character literal, the lexer assumed that
the hash level of escape sequences inside the literal was zero, which
allowed unclosed escape sequences inside the literal which crashed the
compiler.

Closes #6799
Ilya 1 mesiac pred
rodič
commit
6304df1db9

+ 2 - 1
toolchain/lex/string_literal.cpp

@@ -503,7 +503,8 @@ auto StringLiteral::ComputeCharLiteralValue(
   buffer.resize_for_overwrite(content_.size());
 
   auto result = ExpandEscapeSequencesAndRemoveIndent(
-      emitter, content_, 0, /*indent=*/llvm::StringRef(), buffer.data());
+      emitter, content_, hash_level_, /*indent=*/llvm::StringRef(),
+      buffer.data());
   CARBON_CHECK(result.size() <= content_.size(),
                "Content grew from {0} to {1}: `{2}`", content_.size(),
                result.size(), content_);

+ 44 - 4
toolchain/lex/testdata/char_literals.carbon

@@ -82,26 +82,66 @@
 #'a'#
 // CHECK:STDOUT:   - { index:  7, kind: "CharLiteral", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "#'a'#", has_leading_space: true }
 
+// CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:1: error: unexpected `#` before character literal [CharLiteralRaw]
+// CHECK:STDERR: #'\'#
+// CHECK:STDERR: ^
+// CHECK:STDERR:
+#'\'#
+// CHECK:STDOUT:   - { index:  8, kind: "CharLiteral", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "#'\\'#", has_leading_space: true }
+
+// CHECK:STDERR: fail_invalid.carbon:[[@LINE+8]]:1: error: unexpected `#` before character literal [CharLiteralRaw]
+// CHECK:STDERR: ##''##
+// CHECK:STDERR: ^
+// CHECK:STDERR:
+// CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:1: error: empty character literal [CharLiteralEmpty]
+// CHECK:STDERR: ##''##
+// CHECK:STDERR: ^
+// CHECK:STDERR:
+##''##
+// CHECK:STDOUT:   - { index:  9, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "##''##", has_leading_space: true }
+
+// CHECK:STDERR: fail_invalid.carbon:[[@LINE+8]]:1: error: unexpected `#` before character literal [CharLiteralRaw]
+// CHECK:STDERR: #'foo\'#
+// CHECK:STDERR: ^
+// CHECK:STDERR:
+// CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:1: error: too many characters [CharLiteralOverflow]
+// CHECK:STDERR: #'foo\'#
+// CHECK:STDERR: ^
+// CHECK:STDERR:
+#'foo\'#
+// CHECK:STDOUT:   - { index: 10, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "#'foo\\'#", has_leading_space: true }
+
+// CHECK:STDERR: fail_invalid.carbon:[[@LINE+8]]:1: error: unexpected `#` before character literal [CharLiteralRaw]
+// CHECK:STDERR: ##'#\'##
+// CHECK:STDERR: ^
+// CHECK:STDERR:
+// CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:1: error: too many characters [CharLiteralOverflow]
+// CHECK:STDERR: ##'#\'##
+// CHECK:STDERR: ^
+// CHECK:STDERR:
+##'#\'##
+// CHECK:STDOUT:   - { index: 11, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "##'#\\'##", has_leading_space: true }
+
 // CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:1: error: character literal is missing a terminator [UnterminatedString]
 // CHECK:STDERR: '
 // CHECK:STDERR: ^
 // CHECK:STDERR:
 '
-// CHECK:STDOUT:   - { index:  8, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'", has_leading_space: true }
+// CHECK:STDOUT:   - { index: 12, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'", has_leading_space: true }
 
 // CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:1: error: character literal is missing a terminator [UnterminatedString]
 // CHECK:STDERR: '\'
 // CHECK:STDERR: ^
 // CHECK:STDERR:
 '\'
-// CHECK:STDOUT:   - { index:  9, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'\\'", has_leading_space: true }
+// CHECK:STDOUT:   - { index: 13, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'\\'", has_leading_space: true }
 
 // CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:1: error: character literal is missing a terminator [UnterminatedString]
 // CHECK:STDERR: '\
 // CHECK:STDERR: ^
 // CHECK:STDERR:
 '\
-// CHECK:STDOUT:   - { index: 10, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'\\", has_leading_space: true }
+// CHECK:STDOUT:   - { index: 14, kind:       "Error", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'\\", has_leading_space: true }
 
 // This literal contains a raw tab character.
 // CHECK:STDERR: fail_invalid.carbon:[[@LINE+4]]:2: error: whitespace other than plain space must be expressed with an escape sequence in a string literal [InvalidHorizontalWhitespaceInString]
@@ -109,4 +149,4 @@
 // CHECK:STDERR:  ^~~~
 // CHECK:STDERR:
 '	'
-// CHECK:STDOUT:   - { index: 11, kind: "CharLiteral", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'\t'", has_leading_space: true }
+// CHECK:STDOUT:   - { index: 15, kind: "CharLiteral", line: {{ *}}[[@LINE-1]], column:   1, indent: 1, spelling: "'\t'", has_leading_space: true }