Skip to content

Commit 17db054

Browse files
committed
Add TyCtx::env_var_os
Along with `TyCtx::env_var` helper. These can be used to track environment variable accesses in the query system. Since `TyCtx::env_var_os` uses `OsStr`, this commit also adds the necessary trait implementations for that to work.
1 parent c772573 commit 17db054

File tree

6 files changed

+75
-1
lines changed

6 files changed

+75
-1
lines changed

compiler/rustc_data_structures/src/stable_hasher.rs

+2
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,8 @@ where
564564
}
565565
}
566566

567+
impl_stable_traits_for_trivial_type!(::std::ffi::OsStr);
568+
567569
impl_stable_traits_for_trivial_type!(::std::path::Path);
568570
impl_stable_traits_for_trivial_type!(::std::path::PathBuf);
569571

compiler/rustc_interface/src/passes.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::any::Any;
2-
use std::ffi::OsString;
2+
use std::ffi::{OsStr, OsString};
33
use std::io::{self, BufWriter, Write};
44
use std::path::{Path, PathBuf};
55
use std::sync::{Arc, LazyLock, OnceLock};
@@ -361,6 +361,31 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
361361
)
362362
}
363363

364+
fn env_var_os<'tcx>(tcx: TyCtxt<'tcx>, key: &'tcx OsStr) -> Option<&'tcx OsStr> {
365+
let value = env::var_os(key);
366+
367+
let value_tcx = value.as_ref().map(|value| {
368+
let encoded_bytes = tcx.arena.alloc_slice(value.as_encoded_bytes());
369+
debug_assert_eq!(value.as_encoded_bytes(), encoded_bytes);
370+
// SAFETY: The bytes came from `as_encoded_bytes`, and we assume that
371+
// `alloc_slice` is implemented correctly, and passes the same bytes
372+
// back (debug asserted above).
373+
unsafe { OsStr::from_encoded_bytes_unchecked(encoded_bytes) }
374+
});
375+
376+
// Also add the variable to Cargo's dependency tracking
377+
//
378+
// NOTE: This only works for passes run before `write_dep_info`. See that
379+
// for extension points for configuring environment variables to be
380+
// properly change-tracked.
381+
tcx.sess.psess.env_depinfo.borrow_mut().insert((
382+
Symbol::intern(&key.to_string_lossy()),
383+
value.as_ref().and_then(|value| value.to_str()).map(|value| Symbol::intern(&value)),
384+
));
385+
386+
value_tcx
387+
}
388+
364389
// Returns all the paths that correspond to generated files.
365390
fn generated_output_paths(
366391
tcx: TyCtxt<'_>,
@@ -725,6 +750,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
725750
|tcx, _| tcx.arena.alloc_from_iter(tcx.resolutions(()).stripped_cfg_items.steal());
726751
providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
727752
providers.early_lint_checks = early_lint_checks;
753+
providers.env_var_os = env_var_os;
728754
limits::provide(providers);
729755
proc_macro_decls::provide(providers);
730756
rustc_const_eval::provide(providers);

compiler/rustc_middle/src/query/erase.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::ffi::OsStr;
12
use std::intrinsics::transmute_unchecked;
23
use std::mem::MaybeUninit;
34

@@ -67,6 +68,10 @@ impl<T> EraseType for &'_ [T] {
6768
type Result = [u8; size_of::<&'static [()]>()];
6869
}
6970

71+
impl EraseType for &'_ OsStr {
72+
type Result = [u8; size_of::<&'static OsStr>()];
73+
}
74+
7075
impl<T> EraseType for &'_ ty::List<T> {
7176
type Result = [u8; size_of::<&'static ty::List<()>>()];
7277
}
@@ -174,6 +179,10 @@ impl<T> EraseType for Option<&'_ [T]> {
174179
type Result = [u8; size_of::<Option<&'static [()]>>()];
175180
}
176181

182+
impl EraseType for Option<&'_ OsStr> {
183+
type Result = [u8; size_of::<Option<&'static OsStr>>()];
184+
}
185+
177186
impl EraseType for Option<mir::DestructuredConstant<'_>> {
178187
type Result = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()];
179188
}

compiler/rustc_middle/src/query/keys.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Defines the set of legal keys that can be used in queries.
22
3+
use std::ffi::OsStr;
4+
35
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId};
46
use rustc_hir::hir_id::{HirId, OwnerId};
57
use rustc_query_system::dep_graph::DepNodeIndex;
@@ -498,6 +500,14 @@ impl Key for Option<Symbol> {
498500
}
499501
}
500502

503+
impl<'tcx> Key for &'tcx OsStr {
504+
type Cache<V> = DefaultCache<Self, V>;
505+
506+
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
507+
DUMMY_SP
508+
}
509+
}
510+
501511
/// Canonical query goals correspond to abstract trait operations that
502512
/// are not tied to any crate in particular.
503513
impl<'tcx, T: Clone> Key for CanonicalQueryInput<'tcx, T> {

compiler/rustc_middle/src/query/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
#![allow(unused_parens)]
88

9+
use std::ffi::OsStr;
910
use std::mem;
1011
use std::path::PathBuf;
1112
use std::sync::Arc;
@@ -119,6 +120,21 @@ rustc_queries! {
119120
desc { "perform lints prior to AST lowering" }
120121
}
121122

123+
/// Tracked access to environment variables.
124+
///
125+
/// Useful for the implementation of `std::env!`, `proc-macro`s change
126+
/// detection and other changes in the compiler's behaviour that is easier
127+
/// to control with an environment variable than a flag.
128+
///
129+
/// NOTE: This currently does not work with dependency info in the
130+
/// analysis, codegen and linking passes, place extra code at the top of
131+
/// `rustc_interface::passes::write_dep_info` to make that work.
132+
query env_var_os(key: &'tcx OsStr) -> Option<&'tcx OsStr> {
133+
// Environment variables are global state
134+
eval_always
135+
desc { "get the value of an environment variable" }
136+
}
137+
122138
query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt {
123139
no_hash
124140
desc { "getting the resolver outputs" }

compiler/rustc_middle/src/ty/context.rs

+11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ pub mod tls;
77
use std::assert_matches::{assert_matches, debug_assert_matches};
88
use std::borrow::Borrow;
99
use std::cmp::Ordering;
10+
use std::env::VarError;
11+
use std::ffi::OsStr;
1012
use std::hash::{Hash, Hasher};
1113
use std::marker::PhantomData;
1214
use std::ops::{Bound, Deref};
@@ -1882,6 +1884,15 @@ impl<'tcx> TyCtxt<'tcx> {
18821884
}
18831885
None
18841886
}
1887+
1888+
/// Helper to get a tracked environment variable via. [`TyCtxt::env_var_os`] and converting to
1889+
/// UTF-8 like [`std::env::var`].
1890+
pub fn env_var<K: ?Sized + AsRef<OsStr>>(self, key: &'tcx K) -> Result<&'tcx str, VarError> {
1891+
match self.env_var_os(key.as_ref()) {
1892+
Some(value) => value.to_str().ok_or_else(|| VarError::NotUnicode(value.to_os_string())),
1893+
None => Err(VarError::NotPresent),
1894+
}
1895+
}
18851896
}
18861897

18871898
impl<'tcx> TyCtxtAt<'tcx> {

0 commit comments

Comments
 (0)