Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4121,6 +4121,7 @@ version = "0.0.0"
dependencies = [
"cc",
"libc",
"shell-words",
]

[[package]]
Expand Down Expand Up @@ -5115,6 +5116,12 @@ dependencies = [
"lazy_static",
]

[[package]]
name = "shell-words"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"

[[package]]
name = "shlex"
version = "1.3.0"
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
}
}

Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend))
let linker = Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend);

tcx.report_unused_features();

Some(linker)
});

// Linking is done outside the `compiler.enter()` so that the
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
#![allow(rustc::direct_use_of_rustc_type_ir)]
#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(default_field_values)]
#![feature(error_reporter)]
#![feature(macro_metavar_expr_concat)]
#![feature(negative_impls)]
#![feature(never_type)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1330,7 +1330,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
safety: AttributeSafety::Normal,
template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing,
gate: Gated{
gate: Gated {
feature: sym::rustc_attrs,
message: "use of an internal attribute",
check: Features::rustc_attrs,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,5 @@ pub use builtin_attrs::{
pub use removed::REMOVED_LANG_FEATURES;
pub use unstable::{
DEPENDENT_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES,
UNSTABLE_LANG_FEATURES,
TRACK_FEATURE, UNSTABLE_LANG_FEATURES,
};
16 changes: 14 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};

use rustc_data_structures::AtomicRef;
use rustc_data_structures::fx::FxHashSet;
use rustc_span::{Span, Symbol, sym};

use super::{Feature, to_nonzero};

fn default_track_feature(_: Symbol) {}

/// Recording used features in the dependency graph so incremental can
/// replay used features when needed.
pub static TRACK_FEATURE: AtomicRef<fn(Symbol)> = AtomicRef::new(&(default_track_feature as _));

#[derive(PartialEq)]
enum FeatureStatus {
Default,
Expand Down Expand Up @@ -103,7 +110,12 @@ impl Features {

/// Is the given feature enabled (via `#[feature(...)]`)?
pub fn enabled(&self, feature: Symbol) -> bool {
self.enabled_features.contains(&feature)
if self.enabled_features.contains(&feature) {
TRACK_FEATURE(feature);
true
} else {
false
}
}
}

Expand All @@ -124,7 +136,7 @@ macro_rules! declare_features {
impl Features {
$(
pub fn $feature(&self) -> bool {
self.enabled_features.contains(&sym::$feature)
self.enabled(sym::$feature)
}
)*

Expand Down
24 changes: 16 additions & 8 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2416,11 +2416,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Const<'tcx> {
let tcx = self.tcx();

let ty::Array(elem_ty, _) = ty.kind() else {
let e = tcx
.dcx()
.span_err(array_expr.span, format!("expected `{}`, found const array", ty));
return Const::new_error(tcx, e);
let elem_ty = match ty.kind() {
ty::Array(elem_ty, _) => elem_ty,
ty::Error(e) => return Const::new_error(tcx, *e),
_ => {
let e = tcx
.dcx()
.span_err(array_expr.span, format!("expected `{}`, found const array", ty));
return Const::new_error(tcx, e);
}
};

let elems = array_expr
Expand Down Expand Up @@ -2539,9 +2543,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Const<'tcx> {
let tcx = self.tcx();

let ty::Tuple(tys) = ty.kind() else {
let e = tcx.dcx().span_err(span, format!("expected `{}`, found const tuple", ty));
return Const::new_error(tcx, e);
let tys = match ty.kind() {
ty::Tuple(tys) => tys,
ty::Error(e) => return Const::new_error(tcx, *e),
_ => {
let e = tcx.dcx().span_err(span, format!("expected `{}`, found const tuple", ty));
return Const::new_error(tcx, e);
}
};

let exprs = exprs
Expand Down
23 changes: 22 additions & 1 deletion compiler/rustc_interface/src/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
use std::fmt;

use rustc_errors::DiagInner;
use rustc_middle::dep_graph::TaskDepsRef;
use rustc_middle::dep_graph::{DepNodeIndex, QuerySideEffect, TaskDepsRef};
use rustc_middle::ty::tls;
use rustc_span::Symbol;

fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
tls::with_context_opt(|icx| {
Expand Down Expand Up @@ -51,6 +52,25 @@ fn track_diagnostic<R>(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner) -> R)
})
}

fn track_feature(feature: Symbol) {
tls::with_context_opt(|icx| {
let Some(icx) = icx else {
return;
};
let tcx = icx.tcx;

if let Some(dep_node_index) = tcx.sess.used_features.lock().get(&feature).copied() {
tcx.dep_graph.read_index(DepNodeIndex::from_u32(dep_node_index));
} else {
let dep_node_index = tcx
.dep_graph
.encode_side_effect(tcx, QuerySideEffect::CheckFeature { symbol: feature });
tcx.sess.used_features.lock().insert(feature, dep_node_index.as_u32());
tcx.dep_graph.read_index(dep_node_index);
}
})
}

/// This is a callback from `rustc_hir` as it cannot access the implicit state
/// in `rustc_middle` otherwise.
fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -70,4 +90,5 @@ pub fn setup_callbacks() {
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
rustc_errors::TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
rustc_feature::TRACK_FEATURE.swap(&(track_feature as _));
}
5 changes: 0 additions & 5 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,11 +1088,6 @@ declare_lint! {
/// crate-level [`feature` attributes].
///
/// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/
///
/// Note: This lint is currently not functional, see [issue #44232] for
/// more details.
///
/// [issue #44232]: https://github.com/rust-lang/rust/issues/44232
pub UNUSED_FEATURES,
Warn,
"unused features found in crate-level `#[feature]` directives"
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_llvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ libc = "0.2.73"
# tidy-alphabetical-start
# `cc` updates often break things, so we pin it here.
cc = "=1.2.16"
shell-words = "1.1.1"
# tidy-alphabetical-end

[features]
Expand Down
90 changes: 76 additions & 14 deletions compiler/rustc_llvm/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::borrow::Cow;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process::{Command, Output, Stdio};
use std::str::SplitWhitespace;
use std::vec::IntoIter;

const OPTIONAL_COMPONENTS: &[&str] = &[
"x86",
Expand Down Expand Up @@ -86,8 +89,8 @@ fn rerun_if_changed_anything_in_dir(dir: &Path) {
}

#[track_caller]
fn output(cmd: &mut Command) -> String {
let output = match cmd.stderr(Stdio::inherit()).output() {
fn execute(cmd: &mut Command) -> Output {
let output = match cmd.output() {
Ok(status) => status,
Err(e) => {
println!("\n\nfailed to execute command: {cmd:?}\nerror: {e}\n\n");
Expand All @@ -101,7 +104,52 @@ fn output(cmd: &mut Command) -> String {
cmd, output.status
);
}
String::from_utf8(output.stdout).unwrap()
output
}

#[track_caller]
fn output(cmd: &mut Command) -> String {
String::from_utf8(execute(cmd.stderr(Stdio::inherit())).stdout).unwrap()
}
#[track_caller]
fn stderr(cmd: &mut Command) -> String {
String::from_utf8(execute(cmd).stderr).unwrap()
}

enum LlvmConfigOutput {
QuotedPaths(String),
UnquotedPaths(String),
}

#[derive(Clone)]
enum SplitLlvmConfigOutput<'a> {
QuotedPaths(IntoIter<String>),
UnquotedPaths(SplitWhitespace<'a>),
}

impl<'a> Iterator for SplitLlvmConfigOutput<'a> {
type Item = Cow<'a, str>;
fn next(&mut self) -> Option<Cow<'a, str>> {
match self {
Self::QuotedPaths(iter) => iter.next().map(Cow::Owned),
Self::UnquotedPaths(iter) => iter.next().map(Cow::Borrowed),
}
}
}

impl<'a> IntoIterator for &'a LlvmConfigOutput {
type Item = Cow<'a, str>;
type IntoIter = SplitLlvmConfigOutput<'a>;
fn into_iter(self) -> Self::IntoIter {
match self {
LlvmConfigOutput::QuotedPaths(output) => SplitLlvmConfigOutput::QuotedPaths(
shell_words::split(&output).expect("matched quotes").into_iter(),
),
LlvmConfigOutput::UnquotedPaths(output) => {
SplitLlvmConfigOutput::UnquotedPaths(output.split_whitespace())
}
}
}
}

fn main() {
Expand All @@ -125,6 +173,19 @@ fn main() {

println!("cargo:rerun-if-changed={}", llvm_config.display());

// FIXME: `--quote-paths` was added to llvm-config in LLVM 22, so this test (and all its ensuing
// fallback paths) can be removed once we bump the minimum llvm_version >= (22, 0, 0).
let llvm_config_supports_quote_paths =
stderr(Command::new(&llvm_config).arg("--help")).contains("quote-paths");

let quoted_split = |mut cmd: Command| {
if llvm_config_supports_quote_paths {
LlvmConfigOutput::QuotedPaths(output(cmd.arg("--quote-paths")))
} else {
LlvmConfigOutput::UnquotedPaths(output(&mut cmd))
}
};

// Test whether we're cross-compiling LLVM. This is a pretty rare case
// currently where we're producing an LLVM for a different platform than
// what this build script is currently running on.
Expand Down Expand Up @@ -167,7 +228,8 @@ fn main() {
// Link in our own LLVM shims, compiled with the same flags as LLVM
let mut cmd = Command::new(&llvm_config);
cmd.arg("--cxxflags");
let cxxflags = output(&mut cmd);
let cxxflags = quoted_split(cmd);
let mut cxxflags_iter = cxxflags.into_iter();
let mut cfg = cc::Build::new();
cfg.warnings(false);

Expand All @@ -180,7 +242,7 @@ fn main() {
if std::env::var_os("CI").is_some() && !target.contains("msvc") {
cfg.warnings_into_errors(true);
}
for flag in cxxflags.split_whitespace() {
for flag in cxxflags_iter.clone() {
// Ignore flags like `-m64` when we're doing a cross build
if is_crossed && flag.starts_with("-m") {
continue;
Expand All @@ -201,7 +263,7 @@ fn main() {
continue;
}

cfg.flag(flag);
cfg.flag(&*flag);
}

for component in &components {
Expand Down Expand Up @@ -289,13 +351,13 @@ fn main() {
}
cmd.args(&components);

for lib in output(&mut cmd).split_whitespace() {
for lib in &quoted_split(cmd) {
let mut is_static = false;
let name = if let Some(stripped) = lib.strip_prefix("-l") {
stripped
} else if let Some(stripped) = lib.strip_prefix('-') {
stripped
} else if Path::new(lib).exists() {
} else if Path::new(&*lib).exists() {
// On MSVC llvm-config will print the full name to libraries, but
// we're only interested in the name part
// On Unix when we get a static library llvm-config will print the
Expand All @@ -306,7 +368,7 @@ fn main() {
// and we transform the zstd part into
// cargo:rustc-link-search-native=/usr/local/lib
// cargo:rustc-link-lib=static=zstd
let path = Path::new(lib);
let path = Path::new(&*lib);
if lib.ends_with(".a") {
is_static = true;
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
Expand Down Expand Up @@ -351,7 +413,7 @@ fn main() {
// that those -L directories are the same!
let mut cmd = Command::new(&llvm_config);
cmd.arg(llvm_link_arg).arg("--ldflags");
for lib in output(&mut cmd).split_whitespace() {
for lib in &quoted_split(cmd) {
if is_crossed {
if let Some(stripped) = lib.strip_prefix("-LIBPATH:") {
println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target));
Expand All @@ -373,7 +435,7 @@ fn main() {
// dependencies.
let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
if let Some(s) = llvm_linker_flags {
for lib in s.into_string().unwrap().split_whitespace() {
for lib in shell_words::split(&s.into_string().unwrap()).expect("matched quotes") {
if let Some(stripped) = lib.strip_prefix("-l") {
println!("cargo:rustc-link-lib={stripped}");
} else if let Some(stripped) = lib.strip_prefix("-L") {
Expand Down Expand Up @@ -414,15 +476,15 @@ fn main() {
// C++ runtime library
if !target.contains("msvc") {
if let Some(s) = llvm_static_stdcpp {
assert!(!cxxflags.contains("stdlib=libc++"));
assert!(cxxflags_iter.all(|flag| flag != "stdlib=libc++"));
let path = PathBuf::from(s);
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
if target.contains("windows") {
println!("cargo:rustc-link-lib=static:-bundle={stdcppname}");
} else {
println!("cargo:rustc-link-lib=static={stdcppname}");
}
} else if cxxflags.contains("stdlib=libc++") {
} else if cxxflags_iter.any(|flag| flag == "stdlib=libc++") {
println!("cargo:rustc-link-lib=c++");
} else {
println!("cargo:rustc-link-lib={stdcppname}");
Expand Down
Loading
Loading