Rollup merge of #122670 - beetrees:non-unicode-option-env-error, r=compiler-errors
Fix bug where `option_env!` would return `None` when env var is present but not valid Unicode Fixes #122669 by making `option_env!` emit an error when the value of the environment variable is not valid Unicode.
This commit is contained in:
commit
6d9999662c
@ -15,7 +15,7 @@
|
|||||||
use thin_vec::thin_vec;
|
use thin_vec::thin_vec;
|
||||||
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
|
use crate::util::{expr_to_string, get_exprs_from_tts, get_single_expr_from_tts};
|
||||||
|
|
||||||
fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> {
|
fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> {
|
||||||
let var = var.as_str();
|
let var = var.as_str();
|
||||||
@ -32,19 +32,28 @@ pub(crate) fn expand_option_env<'cx>(
|
|||||||
sp: Span,
|
sp: Span,
|
||||||
tts: TokenStream,
|
tts: TokenStream,
|
||||||
) -> MacroExpanderResult<'cx> {
|
) -> MacroExpanderResult<'cx> {
|
||||||
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "option_env!") else {
|
let ExpandResult::Ready(mac_expr) = get_single_expr_from_tts(cx, sp, tts, "option_env!") else {
|
||||||
|
return ExpandResult::Retry(());
|
||||||
|
};
|
||||||
|
let var_expr = match mac_expr {
|
||||||
|
Ok(var_expr) => var_expr,
|
||||||
|
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
|
||||||
|
};
|
||||||
|
let ExpandResult::Ready(mac) =
|
||||||
|
expr_to_string(cx, var_expr.clone(), "argument must be a string literal")
|
||||||
|
else {
|
||||||
return ExpandResult::Retry(());
|
return ExpandResult::Retry(());
|
||||||
};
|
};
|
||||||
let var = match mac {
|
let var = match mac {
|
||||||
Ok(var) => var,
|
Ok((var, _)) => var,
|
||||||
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
|
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let sp = cx.with_def_site_ctxt(sp);
|
let sp = cx.with_def_site_ctxt(sp);
|
||||||
let value = lookup_env(cx, var).ok();
|
let value = lookup_env(cx, var);
|
||||||
cx.sess.psess.env_depinfo.borrow_mut().insert((var, value));
|
cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
|
||||||
let e = match value {
|
let e = match value {
|
||||||
None => {
|
Err(VarError::NotPresent) => {
|
||||||
let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
|
let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
|
||||||
cx.expr_path(cx.path_all(
|
cx.expr_path(cx.path_all(
|
||||||
sp,
|
sp,
|
||||||
@ -58,7 +67,18 @@ pub(crate) fn expand_option_env<'cx>(
|
|||||||
))],
|
))],
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Some(value) => {
|
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(errors::EnvNotUnicode { span: sp, var: *symbol });
|
||||||
|
return ExpandResult::Ready(DummyResult::any(sp, guar));
|
||||||
|
}
|
||||||
|
Ok(value) => {
|
||||||
cx.expr_call_global(sp, cx.std_path(&[sym::option, sym::Option, sym::Some]), thin_vec![
|
cx.expr_call_global(sp, cx.std_path(&[sym::option, sym::Option, sym::Some]), thin_vec![
|
||||||
cx.expr_str(sp, value)
|
cx.expr_str(sp, value)
|
||||||
])
|
])
|
||||||
|
@ -171,6 +171,30 @@ pub(crate) fn get_single_str_spanned_from_tts(
|
|||||||
tts: TokenStream,
|
tts: TokenStream,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> ExpandResult<Result<(Symbol, Span), ErrorGuaranteed>, ()> {
|
) -> ExpandResult<Result<(Symbol, Span), ErrorGuaranteed>, ()> {
|
||||||
|
let ExpandResult::Ready(ret) = get_single_expr_from_tts(cx, span, tts, name) else {
|
||||||
|
return ExpandResult::Retry(());
|
||||||
|
};
|
||||||
|
let ret = match ret {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => return ExpandResult::Ready(Err(e)),
|
||||||
|
};
|
||||||
|
expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| {
|
||||||
|
res.map_err(|err| match err {
|
||||||
|
Ok((err, _)) => err.emit(),
|
||||||
|
Err(guar) => guar,
|
||||||
|
})
|
||||||
|
.map(|(symbol, _style, span)| (symbol, span))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interpreting `tts` as a comma-separated sequence of expressions,
|
||||||
|
/// expect exactly one expression, or emit an error and return `Err`.
|
||||||
|
pub(crate) fn get_single_expr_from_tts(
|
||||||
|
cx: &mut ExtCtxt<'_>,
|
||||||
|
span: Span,
|
||||||
|
tts: TokenStream,
|
||||||
|
name: &str,
|
||||||
|
) -> ExpandResult<Result<P<ast::Expr>, ErrorGuaranteed>, ()> {
|
||||||
let mut p = cx.new_parser_from_tts(tts);
|
let mut p = cx.new_parser_from_tts(tts);
|
||||||
if p.token == token::Eof {
|
if p.token == token::Eof {
|
||||||
let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
|
let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
|
||||||
@ -185,13 +209,7 @@ pub(crate) fn get_single_str_spanned_from_tts(
|
|||||||
if p.token != token::Eof {
|
if p.token != token::Eof {
|
||||||
cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
|
cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
|
||||||
}
|
}
|
||||||
expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| {
|
ExpandResult::Ready(Ok(ret))
|
||||||
res.map_err(|err| match err {
|
|
||||||
Ok((err, _)) => err.emit(),
|
|
||||||
Err(guar) => guar,
|
|
||||||
})
|
|
||||||
.map(|(symbol, _style, span)| (symbol, span))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts comma-separated expressions from `tts`.
|
/// Extracts comma-separated expressions from `tts`.
|
||||||
|
@ -1107,17 +1107,19 @@ macro_rules! env {
|
|||||||
///
|
///
|
||||||
/// If the named environment variable is present at compile time, this will
|
/// If the named environment variable is present at compile time, this will
|
||||||
/// expand into an expression of type `Option<&'static str>` whose value is
|
/// expand into an expression of type `Option<&'static str>` whose value is
|
||||||
/// `Some` of the value of the environment variable. If the environment
|
/// `Some` of the value of the environment variable (a compilation error
|
||||||
/// variable is not present, then this will expand to `None`. See
|
/// will be emitted if the environment variable is not a valid Unicode
|
||||||
/// [`Option<T>`][Option] for more information on this type. Use
|
/// string). If the environment variable is not present, then this will
|
||||||
/// [`std::env::var`] instead if you want to read the value at runtime.
|
/// expand to `None`. See [`Option<T>`][Option] for more information on this
|
||||||
|
/// type. Use [`std::env::var`] instead if you want to read the value at
|
||||||
|
/// runtime.
|
||||||
///
|
///
|
||||||
/// [`std::env::var`]: ../std/env/fn.var.html
|
/// [`std::env::var`]: ../std/env/fn.var.html
|
||||||
///
|
///
|
||||||
/// A compile time error is never emitted when using this macro regardless
|
/// A compile time error is only emitted when using this macro if the
|
||||||
/// of whether the environment variable is present or not.
|
/// environment variable exists and is not a valid Unicode string. To also
|
||||||
/// To emit a compile error if the environment variable is not present,
|
/// emit a compile error if the environment variable is not present, use the
|
||||||
/// use the [`env!`] macro instead.
|
/// [`env!`] macro instead.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
let _ = env!("NON_UNICODE_VAR");
|
let _ = env!("NON_UNICODE_VAR");
|
||||||
|
let _ = option_env!("NON_UNICODE_VAR");
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,13 @@ error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string
|
|||||||
|
|
|
|
||||||
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string
|
||||||
|
--> non_unicode_env.rs:3:13
|
||||||
|
|
|
||||||
|
3 | let _ = option_env!("NON_UNICODE_VAR");
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in the macro `option_env` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user