From ceefd378816ee9abcab5813942711b0d0a0c4fe2 Mon Sep 17 00:00:00 2001 From: arya dradjica Date: Sun, 26 Jul 2026 05:49:27 +0200 Subject: [PATCH 1/2] Add test case for non-unicode `env!` named through macro I've added the expected stderr (computed using the fixed version of the code). As of *this* commit, the last line causes an ICE. --- .../non-unicode-env/non_unicode_env.rs | 8 +++++++ .../non-unicode-env/non_unicode_env.stderr | 21 ++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/run-make/non-unicode-env/non_unicode_env.rs b/tests/run-make/non-unicode-env/non_unicode_env.rs index 3efa4842d94a5..787ccb20e065c 100644 --- a/tests/run-make/non-unicode-env/non_unicode_env.rs +++ b/tests/run-make/non-unicode-env/non_unicode_env.rs @@ -1,4 +1,12 @@ +macro_rules! var_named_via_macro { + () => { + "NON_UNICODE_VAR" + }; +} + fn main() { let _ = env!("NON_UNICODE_VAR"); let _ = option_env!("NON_UNICODE_VAR"); + let _ = env!(var_named_via_macro!()); + let _ = option_env!(var_named_via_macro!()); } diff --git a/tests/run-make/non-unicode-env/non_unicode_env.stderr b/tests/run-make/non-unicode-env/non_unicode_env.stderr index 32868b13f742f..3cfc997b4931e 100644 --- a/tests/run-make/non-unicode-env/non_unicode_env.stderr +++ b/tests/run-make/non-unicode-env/non_unicode_env.stderr @@ -1,14 +1,25 @@ error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string - --> non_unicode_env.rs:2:13 + --> non_unicode_env.rs:8:13 | -2 | let _ = env!("NON_UNICODE_VAR"); +8 | let _ = env!("NON_UNICODE_VAR"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string - --> non_unicode_env.rs:3:13 + --> non_unicode_env.rs:9:13 | -3 | let _ = option_env!("NON_UNICODE_VAR"); +9 | let _ = option_env!("NON_UNICODE_VAR"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string + --> non_unicode_env.rs:10:13 + | +10 | let _ = env!(var_named_via_macro!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string + --> non_unicode_env.rs:11:13 + | +11 | let _ = option_env!(var_named_via_macro!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 4 previous errors From 4f5f05fc1662b7d2d054b92c8d83108185e156d0 Mon Sep 17 00:00:00 2001 From: arya dradjica Date: Sun, 26 Jul 2026 05:55:54 +0200 Subject: [PATCH 2/2] Avoid re-extracting env var name for `[option_]env!` errors The right symbol is already available as `var`, extracted post macro expansion; just use that directly. I have also restructured the `expand_env()` control flow now that there is less shared code, reducing indentation. The primary change there is to use `var` instead of `*symbol`. `var` contains the unescaped name (whereas `symbol` used to store the contents of the original string literal), so `.escape_debug()` is used to re-escape it. The escaping no longer depends on the exact string literal used in the user input, which is quite nice IMO. This required storing `String`s in the diagnostics instead of `Symbol`s. I have added a FIXME to note the accidental double macro expansion occurring in `expand_env()`. It is not a problem, per se, just something that could be cleaned up in the future. --- .../rustc_builtin_macros/src/diagnostics.rs | 8 +- compiler/rustc_builtin_macros/src/env.rs | 86 ++++++++----------- tests/ui/macros/builtin-env-issue-114010.rs | 2 +- .../ui/macros/builtin-env-issue-114010.stderr | 2 +- 4 files changed, 40 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/diagnostics.rs b/compiler/rustc_builtin_macros/src/diagnostics.rs index 6ae0f908a88a0..89ceb2b32381f 100644 --- a/compiler/rustc_builtin_macros/src/diagnostics.rs +++ b/compiler/rustc_builtin_macros/src/diagnostics.rs @@ -562,7 +562,7 @@ pub(crate) enum EnvNotDefined { CargoEnvVar { #[primary_span] span: Span, - var: Symbol, + var: String, var_expr: String, }, #[diag("environment variable `{$var}` not defined at compile time")] @@ -570,7 +570,7 @@ pub(crate) enum EnvNotDefined { CargoEnvVarTypo { #[primary_span] span: Span, - var: Symbol, + var: String, suggested_var: Symbol, }, #[diag("environment variable `{$var}` not defined at compile time")] @@ -578,7 +578,7 @@ pub(crate) enum EnvNotDefined { CustomEnvVar { #[primary_span] span: Span, - var: Symbol, + var: String, var_expr: String, }, } @@ -588,7 +588,7 @@ pub(crate) enum EnvNotDefined { pub(crate) struct EnvNotUnicode { #[primary_span] pub(crate) span: Span, - pub(crate) var: Symbol, + pub(crate) var: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index aaa9117bb092b..38077109b7811 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -6,9 +6,8 @@ use std::env; use std::env::VarError; -use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ExprKind, GenericArg, Mutability}; +use rustc_ast::{GenericArg, Mutability}; use rustc_ast_pretty::pprust; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::edit_distance::edit_distance; @@ -69,14 +68,8 @@ pub(crate) fn expand_option_env<'cx>( )) } Err(VarError::NotUnicode(_)) => { - let ExprKind::Lit(token::Lit { - kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. - }) = &var_expr.kind - else { - unreachable!("`expr_to_string` ensures this is a string lit") - }; - - let guar = cx.dcx().emit_err(diagnostics::EnvNotUnicode { span: sp, var: *symbol }); + let escaped_var = var.as_str().escape_debug().to_string(); + let guar = cx.dcx().emit_err(diagnostics::EnvNotUnicode { span: sp, var: escaped_var }); return ExpandResult::Ready(DummyResult::any(sp, guar)); } Ok(value) => cx.expr_call_global( @@ -106,6 +99,7 @@ pub(crate) fn expand_env<'cx>( }; let var_expr = exprs.next().unwrap(); + // FIXME: `get_exprs_from_tts()` already performed macro expansion... let ExpandResult::Ready(mac) = expr_to_string(cx, var_expr.clone(), "expected string literal") else { return ExpandResult::Retry(()); @@ -133,49 +127,37 @@ pub(crate) fn expand_env<'cx>( let value = lookup_env(cx, var); cx.sess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); let e = match value { - Err(err) => { - let ExprKind::Lit(token::Lit { - kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. - }) = &var_expr.kind - else { - unreachable!("`expr_to_string` ensures this is a string lit") - }; - - let var = var.as_str(); - let guar = match err { - VarError::NotPresent => { - if let Some(msg_from_user) = custom_msg { - cx.dcx().emit_err(diagnostics::EnvNotDefinedWithUserMessage { - span, - msg_from_user, - }) - } else if let Some(suggested_var) = find_similar_cargo_var(var) - && suggested_var != var - { - cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVarTypo { - span, - var: *symbol, - suggested_var: Symbol::intern(suggested_var), - }) - } else if is_cargo_env_var(var) { - cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVar { - span, - var: *symbol, - var_expr: pprust::expr_to_string(&var_expr), - }) - } else { - cx.dcx().emit_err(diagnostics::EnvNotDefined::CustomEnvVar { - span, - var: *symbol, - var_expr: pprust::expr_to_string(&var_expr), - }) - } - } - VarError::NotUnicode(_) => { - cx.dcx().emit_err(diagnostics::EnvNotUnicode { span, var: *symbol }) - } + Err(VarError::NotPresent) => { + let var_str = var.as_str(); + let escaped_var = var_str.escape_debug().to_string(); + let guar = if let Some(msg_from_user) = custom_msg { + cx.dcx().emit_err(diagnostics::EnvNotDefinedWithUserMessage { span, msg_from_user }) + } else if let Some(suggested_var) = find_similar_cargo_var(var_str) + && suggested_var != var_str + { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVarTypo { + span, + var: escaped_var, + suggested_var: Symbol::intern(suggested_var), + }) + } else if is_cargo_env_var(var_str) { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVar { + span, + var: escaped_var, + var_expr: pprust::expr_to_string(&var_expr), + }) + } else { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CustomEnvVar { + span, + var: escaped_var, + var_expr: pprust::expr_to_string(&var_expr), + }) }; - + return ExpandResult::Ready(DummyResult::any(sp, guar)); + } + Err(VarError::NotUnicode(_)) => { + let escaped_var = var.as_str().escape_debug().to_string(); + let guar = cx.dcx().emit_err(diagnostics::EnvNotUnicode { span, var: escaped_var }); return ExpandResult::Ready(DummyResult::any(sp, guar)); } Ok(value) => cx.expr_str(span, value), diff --git a/tests/ui/macros/builtin-env-issue-114010.rs b/tests/ui/macros/builtin-env-issue-114010.rs index 29ccb79a64f8b..3a302b6ed1b06 100644 --- a/tests/ui/macros/builtin-env-issue-114010.rs +++ b/tests/ui/macros/builtin-env-issue-114010.rs @@ -5,6 +5,6 @@ env![r#"oopsie"#]; //~^ ERROR environment variable `oopsie` not defined at compile time env![r#"a""a"#]; -//~^ ERROR environment variable `a""a` not defined at compile time +//~^ ERROR environment variable `a\"\"a` not defined at compile time fn main() {} diff --git a/tests/ui/macros/builtin-env-issue-114010.stderr b/tests/ui/macros/builtin-env-issue-114010.stderr index 2751160e2d467..636fc38fad5a5 100644 --- a/tests/ui/macros/builtin-env-issue-114010.stderr +++ b/tests/ui/macros/builtin-env-issue-114010.stderr @@ -6,7 +6,7 @@ LL | env![r#"oopsie"#]; | = help: use `std::env::var(r#"oopsie"#)` to read the variable at run time -error: environment variable `a""a` not defined at compile time +error: environment variable `a\"\"a` not defined at compile time --> $DIR/builtin-env-issue-114010.rs:7:1 | LL | env![r#"a""a"#];