Skip to content

Rollup of 3 pull requests #142826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 21, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Improve diagnostics for concat_bytes! with C string literals
Use the same error as other invalid types for `concat_bytes!`, rather
than using `ConcatCStrLit` from `concat!`. Also add more information
with a note about why this doesn't work, and a suggestion to use a
null-terminated byte string instead.
  • Loading branch information
tgross35 committed Jun 19, 2025
commit 044c99df78da9464e2ad0a90494af1e584123ab4
2 changes: 2 additions & 0 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
.byte_char = try using a byte character
.byte_str = try using a byte string
.c_str = try using a null-terminated byte string
.c_str_note = concatenating C strings is ambiguous about including the '\0'
.number_array = try wrapping the number in an array

builtin_macros_concat_bytes_missing_literal = expected a byte literal
Expand Down
40 changes: 30 additions & 10 deletions compiler/rustc_builtin_macros/src/concat_bytes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ExprKind, LitIntType, LitKind, UintTy, token};
use rustc_ast::{ExprKind, LitIntType, LitKind, StrStyle, UintTy, token};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_session::errors::report_lit_error;
use rustc_span::{ErrorGuaranteed, Span};
Expand All @@ -21,15 +21,32 @@ fn invalid_type_err(
let snippet = cx.sess.source_map().span_to_snippet(span).ok();
let dcx = cx.dcx();
match LitKind::from_token_lit(token_lit) {
Ok(LitKind::CStr(_, _)) => {
Ok(LitKind::CStr(_, style)) => {
// Avoid ambiguity in handling of terminal `NUL` by refusing to
// concatenate C string literals as bytes.
dcx.emit_err(errors::ConcatCStrLit { span })
let sugg = if let Some(mut as_bstr) = snippet
&& style == StrStyle::Cooked
&& as_bstr.starts_with('c')
&& as_bstr.ends_with('"')
{
// Suggest`c"foo"` -> `b"foo\0"` if we can
as_bstr.replace_range(0..1, "b");
as_bstr.pop();
as_bstr.push_str(r#"\0""#);
Some(ConcatBytesInvalidSuggestion::CStrLit { span, as_bstr })
} else {
// No suggestion for a missing snippet, raw strings, or if for some reason we have
// a span that doesn't match `c"foo"` (possible if a proc macro assigns a span
// that doesn't actually point to a C string).
None
};
// We can only provide a suggestion if we have a snip and it is not a raw string
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "C string", sugg, cs_note: Some(()) })
}
Ok(LitKind::Char(_)) => {
let sugg =
snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg })
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg, cs_note: None })
}
Ok(LitKind::Str(_, _)) => {
// suggestion would be invalid if we are nested
Expand All @@ -38,18 +55,21 @@ fn invalid_type_err(
} else {
None
};
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg })
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg, cs_note: None })
}
Ok(LitKind::Float(_, _)) => {
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None })
}
Ok(LitKind::Bool(_)) => {
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None })
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None, cs_note: None })
}
Ok(LitKind::Bool(_)) => dcx.emit_err(ConcatBytesInvalid {
span,
lit_kind: "boolean",
sugg: None,
cs_note: None,
}),
Ok(LitKind::Int(_, _)) if !is_nested => {
let sugg =
snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet });
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg })
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg, cs_note: None })
}
Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => {
assert!(val.get() > u8::MAX.into()); // must be an error
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ pub(crate) struct ConcatBytesInvalid {
pub(crate) lit_kind: &'static str,
#[subdiagnostic]
pub(crate) sugg: Option<ConcatBytesInvalidSuggestion>,
#[note(builtin_macros_c_str_note)]
pub(crate) cs_note: Option<()>,
}

#[derive(Subdiagnostic)]
Expand All @@ -239,6 +241,13 @@ pub(crate) enum ConcatBytesInvalidSuggestion {
span: Span,
snippet: String,
},
#[note(builtin_macros_c_str_note)]
#[suggestion(builtin_macros_c_str, code = "{as_bstr}", applicability = "machine-applicable")]
CStrLit {
#[primary_span]
span: Span,
as_bstr: String,
},
#[suggestion(
builtin_macros_number_array,
code = "[{snippet}]",
Expand Down
7 changes: 4 additions & 3 deletions tests/ui/macros/concat-bytes-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ fn main() {
//~^ SUGGESTION br"tnrsi"
concat_bytes!(r#"tnrsi"#, r###"tnri"###); //~ ERROR cannot concatenate string literals
//~^ SUGGESTION br#"tnrsi"#
concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate a C string literal
concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate a C string literal
concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate a C string literal
concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate C string literals
//~^ SUGGESTION b"tnrsi\0"
concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate C string literals
concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate C string literals

// Other literals
concat_bytes!(2.8); //~ ERROR cannot concatenate float literals
Expand Down
71 changes: 41 additions & 30 deletions tests/ui/macros/concat-bytes-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -32,106 +32,117 @@ error: cannot concatenate string literals
LL | concat_bytes!(r#"tnrsi"#, r###"tnri"###);
| ^^^^^^^^^^ help: try using a byte string: `br#"tnrsi"#`

error: cannot concatenate a C string literal
error: cannot concatenate C string literals
--> $DIR/concat-bytes-error.rs:18:19
|
LL | concat_bytes!(c"tnrsi", c"tnri");
| ^^^^^^^^ help: try using a null-terminated byte string: `b"tnrsi\0"`
|
note: concatenating C strings is ambiguous about including the '\0'
--> $DIR/concat-bytes-error.rs:18:19
|
LL | concat_bytes!(c"tnrsi", c"tnri");
| ^^^^^^^^
= note: concatenating C strings is ambiguous about including the '\0'

error: cannot concatenate a C string literal
--> $DIR/concat-bytes-error.rs:19:19
error: cannot concatenate C string literals
--> $DIR/concat-bytes-error.rs:20:19
|
LL | concat_bytes!(cr"tnrsi", cr"tnri");
| ^^^^^^^^^
|
= note: concatenating C strings is ambiguous about including the '\0'

error: cannot concatenate a C string literal
--> $DIR/concat-bytes-error.rs:20:19
error: cannot concatenate C string literals
--> $DIR/concat-bytes-error.rs:21:19
|
LL | concat_bytes!(cr#"tnrsi"#, cr###"tnri"###);
| ^^^^^^^^^^^
|
= note: concatenating C strings is ambiguous about including the '\0'

error: cannot concatenate float literals
--> $DIR/concat-bytes-error.rs:23:19
--> $DIR/concat-bytes-error.rs:24:19
|
LL | concat_bytes!(2.8);
| ^^^

error: cannot concatenate numeric literals
--> $DIR/concat-bytes-error.rs:24:19
--> $DIR/concat-bytes-error.rs:25:19
|
LL | concat_bytes!(300);
| ^^^ help: try wrapping the number in an array: `[300]`

error: cannot concatenate character literals
--> $DIR/concat-bytes-error.rs:26:19
--> $DIR/concat-bytes-error.rs:27:19
|
LL | concat_bytes!('a');
| ^^^ help: try using a byte character: `b'a'`

error: cannot concatenate boolean literals
--> $DIR/concat-bytes-error.rs:28:19
--> $DIR/concat-bytes-error.rs:29:19
|
LL | concat_bytes!(true, false);
| ^^^^

error: cannot concatenate numeric literals
--> $DIR/concat-bytes-error.rs:29:19
--> $DIR/concat-bytes-error.rs:30:19
|
LL | concat_bytes!(42, b"va", b'l');
| ^^ help: try wrapping the number in an array: `[42]`

error: cannot concatenate numeric literals
--> $DIR/concat-bytes-error.rs:31:19
--> $DIR/concat-bytes-error.rs:32:19
|
LL | concat_bytes!(42, b"va", b'l', [1, 2]);
| ^^ help: try wrapping the number in an array: `[42]`

error: cannot concatenate string literals
--> $DIR/concat-bytes-error.rs:36:9
--> $DIR/concat-bytes-error.rs:37:9
|
LL | "hi",
| ^^^^

error: cannot concatenate character literals
--> $DIR/concat-bytes-error.rs:39:9
--> $DIR/concat-bytes-error.rs:40:9
|
LL | 'a',
| ^^^ help: try using a byte character: `b'a'`

error: cannot concatenate boolean literals
--> $DIR/concat-bytes-error.rs:43:9
--> $DIR/concat-bytes-error.rs:44:9
|
LL | true,
| ^^^^

error: cannot concatenate boolean literals
--> $DIR/concat-bytes-error.rs:46:9
--> $DIR/concat-bytes-error.rs:47:9
|
LL | false,
| ^^^^^

error: cannot concatenate float literals
--> $DIR/concat-bytes-error.rs:49:9
--> $DIR/concat-bytes-error.rs:50:9
|
LL | 2.6,
| ^^^

error: numeric literal is out of bounds
--> $DIR/concat-bytes-error.rs:52:9
--> $DIR/concat-bytes-error.rs:53:9
|
LL | 265,
| ^^^

error: expected a byte literal
--> $DIR/concat-bytes-error.rs:55:9
--> $DIR/concat-bytes-error.rs:56:9
|
LL | -33,
| ^^^
|
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`

error: cannot concatenate doubly nested array
--> $DIR/concat-bytes-error.rs:58:9
--> $DIR/concat-bytes-error.rs:59:9
|
LL | b"hi!",
| ^^^^^^
Expand All @@ -140,69 +151,69 @@ LL | b"hi!",
= help: try flattening the array

error: cannot concatenate doubly nested array
--> $DIR/concat-bytes-error.rs:61:9
--> $DIR/concat-bytes-error.rs:62:9
|
LL | [5, 6, 7],
| ^^^^^^^^^

error: cannot concatenate numeric literals
--> $DIR/concat-bytes-error.rs:63:19
--> $DIR/concat-bytes-error.rs:64:19
|
LL | concat_bytes!(5u16);
| ^^^^ help: try wrapping the number in an array: `[5u16]`

error: numeric literal is not a `u8`
--> $DIR/concat-bytes-error.rs:65:20
--> $DIR/concat-bytes-error.rs:66:20
|
LL | concat_bytes!([5u16]);
| ^^^^

error: repeat count is not a positive number
--> $DIR/concat-bytes-error.rs:66:23
--> $DIR/concat-bytes-error.rs:67:23
|
LL | concat_bytes!([3; ()]);
| ^^

error: repeat count is not a positive number
--> $DIR/concat-bytes-error.rs:67:23
--> $DIR/concat-bytes-error.rs:68:23
|
LL | concat_bytes!([3; -2]);
| ^^

error: repeat count is not a positive number
--> $DIR/concat-bytes-error.rs:68:25
--> $DIR/concat-bytes-error.rs:69:25
|
LL | concat_bytes!([pie; -2]);
| ^^

error: expected a byte literal
--> $DIR/concat-bytes-error.rs:69:20
--> $DIR/concat-bytes-error.rs:70:20
|
LL | concat_bytes!([pie; 2]);
| ^^^
|
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`

error: cannot concatenate float literals
--> $DIR/concat-bytes-error.rs:70:20
--> $DIR/concat-bytes-error.rs:71:20
|
LL | concat_bytes!([2.2; 0]);
| ^^^

error: repeat count is not a positive number
--> $DIR/concat-bytes-error.rs:71:25
--> $DIR/concat-bytes-error.rs:72:25
|
LL | concat_bytes!([5.5; ()]);
| ^^

error: cannot concatenate doubly nested array
--> $DIR/concat-bytes-error.rs:72:20
--> $DIR/concat-bytes-error.rs:73:20
|
LL | concat_bytes!([[1, 2, 3]; 3]);
| ^^^^^^^^^

error: cannot concatenate doubly nested array
--> $DIR/concat-bytes-error.rs:73:20
--> $DIR/concat-bytes-error.rs:74:20
|
LL | concat_bytes!([[42; 2]; 3]);
| ^^^^^^^
Expand Down
Loading