Skip to content

Commit ffce981

Browse files
authored
Unrolled build for rust-lang#119172
Rollup merge of rust-lang#119172 - nnethercote:earlier-NulInCStr, r=petrochenkov Detect `NulInCStr` error earlier. By making it an `EscapeError` instead of a `LitError`. This makes it like the other errors produced when checking string literals contents, e.g. for invalid escape sequences or bare CR chars. NOTE: this means these errors are issued earlier, before expansion, which changes behaviour. It will be possible to move the check back to the later point if desired. If that happens, it's likely that all the string literal contents checks will be delayed together. One nice thing about this: the old approach had some code in `report_lit_error` to calculate the span of the nul char from a range. This code used a hardwired `+2` to account for the `c"` at the start of a C string literal, but this should have changed to a `+3` for raw C string literals to account for the `cr"`, which meant that the caret in `cr"` nul error messages was one short of where it should have been. The new approach doesn't need any of this and avoids the off-by-one error. r? ```@fee1-dead```
2 parents a34faab + 9018d2c commit ffce981

File tree

11 files changed

+32
-28
lines changed

11 files changed

+32
-28
lines changed

compiler/rustc_ast/src/util/literal.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use rustc_lexer::unescape::{
88
};
99
use rustc_span::symbol::{kw, sym, Symbol};
1010
use rustc_span::Span;
11-
use std::ops::Range;
1211
use std::{ascii, fmt, str};
1312

1413
// Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -39,7 +38,6 @@ pub enum LitError {
3938
InvalidFloatSuffix,
4039
NonDecimalFloat(u32),
4140
IntTooLarge(u32),
42-
NulInCStr(Range<usize>),
4341
}
4442

4543
impl LitKind {
@@ -156,10 +154,7 @@ impl LitKind {
156154
let s = symbol.as_str();
157155
let mut buf = Vec::with_capacity(s.len());
158156
let mut error = Ok(());
159-
unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
160-
Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
161-
error = Err(LitError::NulInCStr(span));
162-
}
157+
unescape_c_string(s, Mode::CStr, &mut |_span, c| match c {
163158
Ok(CStrUnit::Byte(b)) => buf.push(b),
164159
Ok(CStrUnit::Char(c)) => {
165160
buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
@@ -179,10 +174,7 @@ impl LitKind {
179174
// can convert the symbol directly to a `Lrc<u8>` on success.
180175
let s = symbol.as_str();
181176
let mut error = Ok(());
182-
unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
183-
Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
184-
error = Err(LitError::NulInCStr(span));
185-
}
177+
unescape_c_string(s, Mode::RawCStr, &mut |_, c| match c {
186178
Ok(_) => {}
187179
Err(err) => {
188180
if err.is_fatal() {

compiler/rustc_lexer/src/unescape.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ pub enum EscapeError {
5959
/// Non-ascii character in byte literal, byte string literal, or raw byte string literal.
6060
NonAsciiCharInByte,
6161

62+
// `\0` in a C string literal.
63+
NulInCStr,
64+
6265
/// After a line ending with '\', the next line contains whitespace
6366
/// characters that are not skipped.
6467
UnskippedWhitespaceWarning,
@@ -122,10 +125,20 @@ where
122125
{
123126
match mode {
124127
CStr => {
125-
unescape_non_raw_common(src, mode, callback);
128+
unescape_non_raw_common(src, mode, &mut |r, mut result| {
129+
if let Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) = result {
130+
result = Err(EscapeError::NulInCStr);
131+
}
132+
callback(r, result)
133+
});
126134
}
127135
RawCStr => {
128-
check_raw_common(src, mode, &mut |r, result| callback(r, result.map(CStrUnit::Char)));
136+
check_raw_common(src, mode, &mut |r, mut result| {
137+
if let Ok('\0') = result {
138+
result = Err(EscapeError::NulInCStr);
139+
}
140+
callback(r, result.map(CStrUnit::Char))
141+
});
129142
}
130143
Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(),
131144
}

compiler/rustc_parse/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable
616616
617617
parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
618618
619+
parse_nul_in_c_str = null characters in C string literals are not supported
620+
619621
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
620622
parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
621623
parse_out_of_range_hex_escape = out of range hex escape

compiler/rustc_parse/src/errors.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2163,6 +2163,11 @@ pub enum UnescapeError {
21632163
#[subdiagnostic]
21642164
suggestion: MoreThanOneCharSugg,
21652165
},
2166+
#[diag(parse_nul_in_c_str)]
2167+
NulInCStr {
2168+
#[primary_span]
2169+
span: Span,
2170+
},
21662171
}
21672172

21682173
#[derive(Subdiagnostic)]

compiler/rustc_parse/src/lexer/unescape_error_reporting.rs

+3
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ pub(crate) fn emit_unescape_error(
262262
EscapeError::LoneSlash => {
263263
dcx.emit_err(UnescapeError::LoneSlash(err_span));
264264
}
265+
EscapeError::NulInCStr => {
266+
dcx.emit_err(UnescapeError::NulInCStr { span: err_span });
267+
}
265268
EscapeError::UnskippedWhitespaceWarning => {
266269
let (c, char_span) = last_char();
267270
dcx.emit_warn(UnescapeError::UnskippedWhitespace {

compiler/rustc_session/messages.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be u
7575
7676
session_not_supported = not supported
7777
78-
session_nul_in_c_str = null characters in C string literals are not supported
79-
8078
session_octal_float_literal_not_supported = octal float literal is not supported
8179
8280
session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}

compiler/rustc_session/src/errors.rs

+1-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::{
66
error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan,
77
};
88
use rustc_macros::Diagnostic;
9-
use rustc_span::{BytePos, Span, Symbol};
9+
use rustc_span::{Span, Symbol};
1010
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
1111

1212
use crate::parse::ParseSess;
@@ -346,13 +346,6 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
346346
pub span: Span,
347347
}
348348

349-
#[derive(Diagnostic)]
350-
#[diag(session_nul_in_c_str)]
351-
pub(crate) struct NulInCStr {
352-
#[primary_span]
353-
pub span: Span,
354-
}
355-
356349
pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
357350
// Checks if `s` looks like i32 or u1234 etc.
358351
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -432,12 +425,6 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
432425
};
433426
dcx.emit_err(IntLiteralTooLarge { span, limit });
434427
}
435-
LitError::NulInCStr(range) => {
436-
let lo = BytePos(span.lo().0 + range.start as u32 + 2);
437-
let hi = BytePos(span.lo().0 + range.end as u32 + 2);
438-
let span = span.with_lo(lo).with_hi(hi);
439-
dcx.emit_err(NulInCStr { span });
440-
}
441428
}
442429
}
443430

src/tools/rust-analyzer/crates/parser/src/lexed_str.rs

+1
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str {
369369
"non-ASCII character in byte string literal"
370370
}
371371
EscapeError::NonAsciiCharInByte => "non-ASCII character in raw byte string literal",
372+
EscapeError::NulInCStr => "null character in C string literal",
372373
EscapeError::UnskippedWhitespaceWarning => "",
373374
EscapeError::MultipleSkippedLinesWarning => "",
374375
}

src/tools/rust-analyzer/crates/syntax/src/validation.rs

+3
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str,
106106
EE::NonAsciiCharInByte => {
107107
"Byte literals must not contain non-ASCII characters"
108108
}
109+
EE::NulInCStr => {
110+
"C strings literals must not contain null characters"
111+
}
109112
EE::UnskippedWhitespaceWarning => "Whitespace after this escape is not skipped",
110113
EE::MultipleSkippedLinesWarning => "Multiple lines are skipped by this escape",
111114

Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)