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.
This commit is contained in:
commit
8ecaf2ae57
@ -109,8 +109,8 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept
|
||||
.suggestion = remove the value
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead
|
||||
.other = use `std::env::var("{$var}")` to read the variable at run time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
|
||||
.custom = use `std::env::var({$var_expr})` to read the variable at run time
|
||||
|
||||
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{self as ast, GenericArg};
|
||||
use rustc_ast::{self as ast, AstDeref, GenericArg};
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
@ -76,27 +76,36 @@ pub fn expand_env<'cx>(
|
||||
},
|
||||
};
|
||||
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
let span = cx.with_def_site_ctxt(sp);
|
||||
let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern);
|
||||
cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
|
||||
let e = match value {
|
||||
None => {
|
||||
// Use the string literal in the code in the diagnostic to avoid confusing diagnostics,
|
||||
// e.g. when the literal contains escape sequences.
|
||||
let ast::ExprKind::Lit(ast::token::Lit {
|
||||
kind: ast::token::LitKind::Str,
|
||||
symbol: original_var,
|
||||
kind: ast::token::LitKind::Str | ast::token::LitKind::StrRaw(..),
|
||||
symbol,
|
||||
..
|
||||
}) = &var_expr.kind
|
||||
else {
|
||||
unreachable!("`expr_to_string` ensures this is a string lit")
|
||||
};
|
||||
cx.emit_err(errors::EnvNotDefined {
|
||||
span: sp,
|
||||
msg: custom_msg,
|
||||
var: *original_var,
|
||||
help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())),
|
||||
});
|
||||
|
||||
if let Some(msg_from_user) = custom_msg {
|
||||
cx.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
|
||||
} else if is_cargo_env_var(var.as_str()) {
|
||||
cx.emit_err(errors::EnvNotDefined::CargoEnvVar {
|
||||
span,
|
||||
var: *symbol,
|
||||
var_expr: var_expr.ast_deref(),
|
||||
});
|
||||
} else {
|
||||
cx.emit_err(errors::EnvNotDefined::CustomEnvVar {
|
||||
span,
|
||||
var: *symbol,
|
||||
var_expr: var_expr.ast_deref(),
|
||||
});
|
||||
}
|
||||
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
Some(value) => cx.expr_str(sp, value),
|
||||
@ -104,13 +113,9 @@ pub fn expand_env<'cx>(
|
||||
MacEager::expr(e)
|
||||
}
|
||||
|
||||
fn help_for_missing_env_var(var: &str) -> errors::EnvNotDefinedHelp {
|
||||
if var.starts_with("CARGO_")
|
||||
/// Returns `true` if an environment variable from `env!` is one used by Cargo.
|
||||
fn is_cargo_env_var(var: &str) -> bool {
|
||||
var.starts_with("CARGO_")
|
||||
|| var.starts_with("DEP_")
|
||||
|| matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
|
||||
{
|
||||
errors::EnvNotDefinedHelp::CargoVar
|
||||
} else {
|
||||
errors::EnvNotDefinedHelp::Other
|
||||
}
|
||||
}
|
||||
|
@ -440,43 +440,43 @@ pub(crate) struct EnvTakesArgs {
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
//#[derive(Diagnostic)]
|
||||
//#[diag(builtin_macros_env_not_defined)]
|
||||
pub(crate) struct EnvNotDefined {
|
||||
pub(crate) struct EnvNotDefinedWithUserMessage {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) msg: Option<Symbol>,
|
||||
pub(crate) var: Symbol,
|
||||
pub(crate) help: Option<EnvNotDefinedHelp>,
|
||||
pub(crate) msg_from_user: Symbol,
|
||||
}
|
||||
|
||||
// Hand-written implementation to support custom user messages
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
|
||||
// Hand-written implementation to support custom user messages.
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage {
|
||||
#[track_caller]
|
||||
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
|
||||
let mut diag = if let Some(msg) = self.msg {
|
||||
#[expect(
|
||||
rustc::untranslatable_diagnostic,
|
||||
reason = "cannot translate user-provided messages"
|
||||
)]
|
||||
handler.struct_diagnostic(msg.to_string())
|
||||
} else {
|
||||
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
|
||||
};
|
||||
diag.set_arg("var", self.var);
|
||||
#[expect(
|
||||
rustc::untranslatable_diagnostic,
|
||||
reason = "cannot translate user-provided messages"
|
||||
)]
|
||||
let mut diag = handler.struct_diagnostic(self.msg_from_user.to_string());
|
||||
diag.set_span(self.span);
|
||||
if let Some(help) = self.help {
|
||||
diag.subdiagnostic(help);
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum EnvNotDefinedHelp {
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum EnvNotDefined<'a> {
|
||||
#[diag(builtin_macros_env_not_defined)]
|
||||
#[help(builtin_macros_cargo)]
|
||||
CargoVar,
|
||||
#[help(builtin_macros_other)]
|
||||
Other,
|
||||
CargoEnvVar {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: Symbol,
|
||||
var_expr: &'a rustc_ast::Expr,
|
||||
},
|
||||
#[diag(builtin_macros_env_not_defined)]
|
||||
#[help(builtin_macros_custom)]
|
||||
CustomEnvVar {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: Symbol,
|
||||
var_expr: &'a rustc_ast::Expr,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -164,6 +164,12 @@ impl IntoDiagnosticArg for hir::ConstContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for ast::Expr {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(pprust::expr_to_string(&self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for ast::Path {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
|
||||
|
@ -328,7 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
||||
{
|
||||
// Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
|
||||
// `&[u8]`. This change would prevent matching with different sized slices.
|
||||
} else {
|
||||
} else if !callsite.starts_with("env!") {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_LIT_AS_BYTES,
|
||||
|
10
tests/ui/macros/builtin-env-issue-114010.rs
Normal file
10
tests/ui/macros/builtin-env-issue-114010.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// unset-rustc-env:oopsie
|
||||
// unset-rustc-env:a""a
|
||||
|
||||
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
|
||||
|
||||
fn main() {}
|
20
tests/ui/macros/builtin-env-issue-114010.stderr
Normal file
20
tests/ui/macros/builtin-env-issue-114010.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error: environment variable `oopsie` not defined at compile time
|
||||
--> $DIR/builtin-env-issue-114010.rs:4:1
|
||||
|
|
||||
LL | env![r#"oopsie"#];
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `std::env::var(r#"oopsie"#)` to read the variable at run time
|
||||
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: environment variable `a""a` not defined at compile time
|
||||
--> $DIR/builtin-env-issue-114010.rs:7:1
|
||||
|
|
||||
LL | env![r#"a""a"#];
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `std::env::var(r#"a""a"#)` to read the variable at run time
|
||||
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user