소스 검색

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 개월 전
부모
커밋
6304df1db9
2개의 변경된 파일46개의 추가작업 그리고 5개의 파일을 삭제
  1. 2 1
      toolchain/lex/string_literal.cpp
  2. 44 4
      toolchain/lex/testdata/char_literals.carbon

+ 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 }