Skip to content

Commit 8ecaf2a

Browse files
authored
Rollup merge of #114014 - davidtwco:issue-114010-env-rawstr, r=cjgillot
builtin_macros: expect raw strings too Fixes #114010. `expr_to_string` allows raw strings through so this code should be expected to handle those.
2 parents 24e34e2 + 516a565 commit 8ecaf2a

File tree

7 files changed

+89
-48
lines changed

7 files changed

+89
-48
lines changed

Diff for: compiler/rustc_builtin_macros/messages.ftl

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept
109109
.suggestion = remove the value
110110
111111
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
112-
.cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead
113-
.other = use `std::env::var("{$var}")` to read the variable at run time
112+
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
113+
.custom = use `std::env::var({$var_expr})` to read the variable at run time
114114
115115
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
116116

Diff for: compiler/rustc_builtin_macros/src/env.rs

+24-19
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//
55

66
use rustc_ast::tokenstream::TokenStream;
7-
use rustc_ast::{self as ast, GenericArg};
7+
use rustc_ast::{self as ast, AstDeref, GenericArg};
88
use rustc_expand::base::{self, *};
99
use rustc_span::symbol::{kw, sym, Ident, Symbol};
1010
use rustc_span::Span;
@@ -76,41 +76,46 @@ pub fn expand_env<'cx>(
7676
},
7777
};
7878

79-
let sp = cx.with_def_site_ctxt(sp);
79+
let span = cx.with_def_site_ctxt(sp);
8080
let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern);
8181
cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
8282
let e = match value {
8383
None => {
84-
// Use the string literal in the code in the diagnostic to avoid confusing diagnostics,
85-
// e.g. when the literal contains escape sequences.
8684
let ast::ExprKind::Lit(ast::token::Lit {
87-
kind: ast::token::LitKind::Str,
88-
symbol: original_var,
85+
kind: ast::token::LitKind::Str | ast::token::LitKind::StrRaw(..),
86+
symbol,
8987
..
9088
}) = &var_expr.kind
9189
else {
9290
unreachable!("`expr_to_string` ensures this is a string lit")
9391
};
94-
cx.emit_err(errors::EnvNotDefined {
95-
span: sp,
96-
msg: custom_msg,
97-
var: *original_var,
98-
help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())),
99-
});
92+
93+
if let Some(msg_from_user) = custom_msg {
94+
cx.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
95+
} else if is_cargo_env_var(var.as_str()) {
96+
cx.emit_err(errors::EnvNotDefined::CargoEnvVar {
97+
span,
98+
var: *symbol,
99+
var_expr: var_expr.ast_deref(),
100+
});
101+
} else {
102+
cx.emit_err(errors::EnvNotDefined::CustomEnvVar {
103+
span,
104+
var: *symbol,
105+
var_expr: var_expr.ast_deref(),
106+
});
107+
}
108+
100109
return DummyResult::any(sp);
101110
}
102111
Some(value) => cx.expr_str(sp, value),
103112
};
104113
MacEager::expr(e)
105114
}
106115

107-
fn help_for_missing_env_var(var: &str) -> errors::EnvNotDefinedHelp {
108-
if var.starts_with("CARGO_")
116+
/// Returns `true` if an environment variable from `env!` is one used by Cargo.
117+
fn is_cargo_env_var(var: &str) -> bool {
118+
var.starts_with("CARGO_")
109119
|| var.starts_with("DEP_")
110120
|| matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
111-
{
112-
errors::EnvNotDefinedHelp::CargoVar
113-
} else {
114-
errors::EnvNotDefinedHelp::Other
115-
}
116121
}

Diff for: compiler/rustc_builtin_macros/src/errors.rs

+26-26
Original file line numberDiff line numberDiff line change
@@ -440,43 +440,43 @@ pub(crate) struct EnvTakesArgs {
440440
pub(crate) span: Span,
441441
}
442442

443-
//#[derive(Diagnostic)]
444-
//#[diag(builtin_macros_env_not_defined)]
445-
pub(crate) struct EnvNotDefined {
443+
pub(crate) struct EnvNotDefinedWithUserMessage {
446444
pub(crate) span: Span,
447-
pub(crate) msg: Option<Symbol>,
448-
pub(crate) var: Symbol,
449-
pub(crate) help: Option<EnvNotDefinedHelp>,
445+
pub(crate) msg_from_user: Symbol,
450446
}
451447

452-
// Hand-written implementation to support custom user messages
453-
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
448+
// Hand-written implementation to support custom user messages.
449+
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage {
454450
#[track_caller]
455451
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
456-
let mut diag = if let Some(msg) = self.msg {
457-
#[expect(
458-
rustc::untranslatable_diagnostic,
459-
reason = "cannot translate user-provided messages"
460-
)]
461-
handler.struct_diagnostic(msg.to_string())
462-
} else {
463-
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
464-
};
465-
diag.set_arg("var", self.var);
452+
#[expect(
453+
rustc::untranslatable_diagnostic,
454+
reason = "cannot translate user-provided messages"
455+
)]
456+
let mut diag = handler.struct_diagnostic(self.msg_from_user.to_string());
466457
diag.set_span(self.span);
467-
if let Some(help) = self.help {
468-
diag.subdiagnostic(help);
469-
}
470458
diag
471459
}
472460
}
473461

474-
#[derive(Subdiagnostic)]
475-
pub(crate) enum EnvNotDefinedHelp {
462+
#[derive(Diagnostic)]
463+
pub(crate) enum EnvNotDefined<'a> {
464+
#[diag(builtin_macros_env_not_defined)]
476465
#[help(builtin_macros_cargo)]
477-
CargoVar,
478-
#[help(builtin_macros_other)]
479-
Other,
466+
CargoEnvVar {
467+
#[primary_span]
468+
span: Span,
469+
var: Symbol,
470+
var_expr: &'a rustc_ast::Expr,
471+
},
472+
#[diag(builtin_macros_env_not_defined)]
473+
#[help(builtin_macros_custom)]
474+
CustomEnvVar {
475+
#[primary_span]
476+
span: Span,
477+
var: Symbol,
478+
var_expr: &'a rustc_ast::Expr,
479+
},
480480
}
481481

482482
#[derive(Diagnostic)]

Diff for: compiler/rustc_errors/src/diagnostic_impls.rs

+6
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ impl IntoDiagnosticArg for hir::ConstContext {
164164
}
165165
}
166166

167+
impl IntoDiagnosticArg for ast::Expr {
168+
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
169+
DiagnosticArgValue::Str(Cow::Owned(pprust::expr_to_string(&self)))
170+
}
171+
}
172+
167173
impl IntoDiagnosticArg for ast::Path {
168174
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
169175
DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))

Diff for: src/tools/clippy/clippy_lints/src/strings.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
328328
{
329329
// Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
330330
// `&[u8]`. This change would prevent matching with different sized slices.
331-
} else {
331+
} else if !callsite.starts_with("env!") {
332332
span_lint_and_sugg(
333333
cx,
334334
STRING_LIT_AS_BYTES,

Diff for: tests/ui/macros/builtin-env-issue-114010.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// unset-rustc-env:oopsie
2+
// unset-rustc-env:a""a
3+
4+
env![r#"oopsie"#];
5+
//~^ ERROR environment variable `oopsie` not defined at compile time
6+
7+
env![r#"a""a"#];
8+
//~^ ERROR environment variable `a""a` not defined at compile time
9+
10+
fn main() {}

Diff for: tests/ui/macros/builtin-env-issue-114010.stderr

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: environment variable `oopsie` not defined at compile time
2+
--> $DIR/builtin-env-issue-114010.rs:4:1
3+
|
4+
LL | env![r#"oopsie"#];
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= help: use `std::env::var(r#"oopsie"#)` to read the variable at run time
8+
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
9+
10+
error: environment variable `a""a` not defined at compile time
11+
--> $DIR/builtin-env-issue-114010.rs:7:1
12+
|
13+
LL | env![r#"a""a"#];
14+
| ^^^^^^^^^^^^^^^
15+
|
16+
= help: use `std::env::var(r#"a""a"#)` to read the variable at run time
17+
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
18+
19+
error: aborting due to 2 previous errors
20+

0 commit comments

Comments
 (0)