Skip to content
Closed
23 changes: 23 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
check_incompatible_features(sess, features);
check_dependent_features(sess, features);
check_new_solver_banned_features(sess, features);
check_features_requiring_new_solver(sess, features);

let mut visitor = PostExpansionVisitor { sess, features };

Expand Down Expand Up @@ -739,3 +740,25 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) {
});
}
}

fn check_features_requiring_new_solver(sess: &Session, features: &Features) {
if sess.opts.unstable_opts.next_solver.globally {
return;
}

// Require the new solver with GCA, because the old solver can't implement GCA correctly as it
// does not support normalization obligations for free and inherent consts.
if let Some(gca_span) = features
.enabled_lang_features()
.iter()
.find(|feat| feat.gate_name == sym::generic_const_args)
.map(|feat| feat.attr_sp)
{
#[allow(rustc::symbol_intern_string_literal)]
sess.dcx().emit_err(errors::MissingDependentFeatures {
parent_span: gca_span,
parent: sym::generic_const_args,
missing: String::from("-Znext-solver=globally"),
});
}
}
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_gcc/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ use std::path::{Path, PathBuf};
use gccjit::OutputKind;
use object::read::archive::ArchiveFile;
use rustc_codegen_ssa::back::lto::SerializedModule;
use rustc_codegen_ssa::back::rmeta_link;
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file};
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_errors::{DiagCtxt, DiagCtxtHandle};
Expand Down Expand Up @@ -63,6 +64,7 @@ fn prepare_lto(each_linked_rlib_for_lto: &[PathBuf], dcx: DiagCtxtHandle<'_>) ->
let archive_data = unsafe {
Mmap::map(File::open(path).expect("couldn't open rlib")).expect("couldn't map rlib")
};
let metadata_link = rmeta_link::read_from_data(&archive_data, path).unwrap();
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
let obj_files = archive
.members()
Expand All @@ -71,7 +73,7 @@ fn prepare_lto(each_linked_rlib_for_lto: &[PathBuf], dcx: DiagCtxtHandle<'_>) ->
.ok()
.and_then(|c| std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)))
})
.filter(|&(name, _)| looks_like_rust_object_file(name));
.filter(|&(name, _)| metadata_link.rust_object_files.iter().any(|f| f == name));
for (name, child) in obj_files {
info!("adding bitcode from {}", name);
let path = tmp_path.path().join(name);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ use std::{io, iter, slice};
use object::read::archive::ArchiveFile;
use object::{Object, ObjectSection};
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::rmeta_link;
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, SharedEmitter, TargetMachineFactoryFn, ThinLtoInput,
};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file};
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
Expand Down Expand Up @@ -96,14 +97,15 @@ fn prepare_lto(
.expect("couldn't map rlib")
};
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
let metadata_link = rmeta_link::read(&archive, &archive_data, &path).unwrap();
let obj_files = archive
.members()
.filter_map(|child| {
child
.ok()
.and_then(|c| std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)))
})
.filter(|&(name, _)| looks_like_rust_object_file(name));
.filter(|&(name, _)| metadata_link.rust_object_files.iter().any(|f| f == name));
for (name, child) in obj_files {
info!("adding bitcode from {}", name);
match get_bitcode_slice_from_object_data(
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use rustc_target::spec::Arch;
use tracing::trace;

use super::metadata::{create_compressed_metadata_file, search_for_section};
use super::rmeta_link::{self, RmetaLink};
use crate::common;
// Public for ArchiveBuilderBuilder::extract_bundled_libs
pub use crate::errors::ExtractBundledLibsError;
Expand Down Expand Up @@ -313,7 +314,7 @@ pub trait ArchiveBuilder {
fn add_archive(
&mut self,
archive: &Path,
skip: Box<dyn FnMut(&str) -> bool + 'static>,
skip: Option<Box<dyn FnMut(&str, Option<&RmetaLink>) -> bool + 'static>>,
) -> io::Result<()>;

fn build(self: Box<Self>, output: &Path) -> bool;
Expand Down Expand Up @@ -445,7 +446,7 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
fn add_archive(
&mut self,
archive_path: &Path,
mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
mut skip: Option<Box<dyn FnMut(&str, Option<&RmetaLink>) -> bool + 'static>>,
) -> io::Result<()> {
let mut archive_path = archive_path.to_path_buf();
if self.sess.target.llvm_target.contains("-apple-macosx")
Expand All @@ -461,6 +462,8 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
let archive = ArchiveFile::parse(&*archive_map)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
let metadata_link =
skip.as_ref().and_then(|_| rmeta_link::read(&archive, &archive_map, &archive_path));
let archive_index = self.src_archives.len();

if let Some(expected_kind) =
Expand All @@ -480,7 +483,8 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
let file_name = String::from_utf8(entry.name().to_vec())
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
if !skip(&file_name) {
let drop = skip.as_mut().is_some_and(|f| f(&file_name, metadata_link.as_ref()));
if !drop {
if entry.is_thin() {
let member_path = archive_path.parent().unwrap().join(Path::new(&file_name));
self.entries.push((file_name.into_bytes(), ArchiveEntry::File(member_path)));
Expand Down
69 changes: 48 additions & 21 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,9 @@ use super::command::Command;
use super::linker::{self, Linker};
use super::metadata::{MetadataPosition, create_wrapper_file};
use super::rpath::{self, RPathConfig};
use super::{apple, versioned_llvm_target};
use super::{apple, rmeta_link, versioned_llvm_target};
use crate::base::needs_allocator_shim_for_linking;
use crate::{
CodegenLintLevels, CompiledModule, CompiledModules, CrateInfo, NativeLib, errors,
looks_like_rust_object_file,
};
use crate::{CodegenLintLevels, CompiledModule, CompiledModules, CrateInfo, NativeLib, errors};

pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
if let Err(e) = fs::remove_file(path) {
Expand Down Expand Up @@ -307,6 +304,27 @@ fn link_rlib<'a>(
) -> Box<dyn ArchiveBuilder + 'a> {
let mut ab = archive_builder_builder.new_archive_builder(sess);

// Pre-compute the list of Rust object filenames and materialize the rmeta-link
// wrapper file before any `add_file` calls. This lets the rmeta-link member be
// placed immediately after metadata in the archive, so consumers can find
// it without iterating every archive member.
let rust_object_files: Vec<String> = compiled_modules
.modules
.iter()
.filter_map(|m| m.object.as_ref())
.map(|obj| obj.file_name().unwrap().to_str().unwrap().to_string())
.collect();

let metadata_link_file = if matches!(flavor, RlibFlavor::Normal) {
let metadata_link = rmeta_link::RmetaLink { rust_object_files };
let metadata_link_data = metadata_link.encode();
let (wrapper, _) =
create_wrapper_file(sess, rmeta_link::SECTION.to_string(), &metadata_link_data);
Some(emit_wrapper_file(sess, &wrapper, tmpdir.as_ref(), rmeta_link::FILENAME))
} else {
None
};

let trailing_metadata = match flavor {
RlibFlavor::Normal => {
let (metadata, metadata_position) =
Expand All @@ -320,6 +338,11 @@ fn link_rlib<'a>(
// If it is possible however, placing the metadata object first improves
// performance of getting metadata from rlibs.
ab.add_file(&metadata);
// Place the rmeta-link member immediately after metadata so consumers
// can find it without iterating the whole archive.
if let Some(file) = &metadata_link_file {
ab.add_file(file);
}
None
}
MetadataPosition::Last => Some(metadata),
Expand Down Expand Up @@ -383,7 +406,7 @@ fn link_rlib<'a>(
packed_bundled_libs.push(wrapper_file);
} else {
let path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
ab.add_archive(&path, None).unwrap_or_else(|error| {
sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: path, error })
});
}
Expand All @@ -400,7 +423,7 @@ fn link_rlib<'a>(
tmpdir.as_ref(),
true,
) {
ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
ab.add_archive(&output_path, None).unwrap_or_else(|error| {
sess.dcx()
.emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
});
Expand Down Expand Up @@ -434,6 +457,11 @@ fn link_rlib<'a>(
// Basically, all this means is that this code should not move above the
// code above.
ab.add_file(&trailing_metadata);
// Place the rmeta-link member immediately after metadata so consumers can
// find it without iterating the whole archive.
if let Some(file) = &metadata_link_file {
ab.add_file(file);
}
}

// Add all bundled static native library dependencies.
Expand Down Expand Up @@ -488,14 +516,16 @@ fn link_staticlib(
let bundled_libs: FxIndexSet<_> = native_libs.filter_map(|lib| lib.filename).collect();
ab.add_archive(
path,
Box::new(move |fname: &str| {
// Ignore metadata files, no matter the name.
if fname == METADATA_FILENAME {
Some(Box::new(move |fname: &str, metadata_link| {
// Ignore metadata and rmeta-link files.
if fname == METADATA_FILENAME || fname == rmeta_link::FILENAME {
return true;
}

// Don't include Rust objects if LTO is enabled
if lto && looks_like_rust_object_file(fname) {
// Don't include Rust objects if LTO is enabled.
if lto
&& metadata_link.is_some_and(|m| m.rust_object_files.iter().any(|f| f == fname))
{
return true;
}

Expand All @@ -505,7 +535,7 @@ fn link_staticlib(
}

false
}),
})),
)
.unwrap();

Expand All @@ -516,7 +546,7 @@ fn link_staticlib(
for filename in relevant_libs.iter() {
let joined = tempdir.as_ref().join(filename.as_str());
let path = joined.as_path();
ab.add_archive(path, Box::new(|_| false)).unwrap();
ab.add_archive(path, None).unwrap();
}

all_native_libs.extend(crate_info.native_libraries[&cnum].iter().cloned());
Expand Down Expand Up @@ -3167,23 +3197,20 @@ fn add_static_crate(
let bundled_lib_file_names = bundled_lib_file_names.clone();

sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
let canonical_name = name.replace('-', "_");
let upstream_rust_objects_already_included =
are_upstream_rust_objects_already_included(sess);
let is_builtins = sess.target.no_builtins || !crate_info.is_no_builtins.contains(&cnum);

let mut archive = archive_builder_builder.new_archive_builder(sess);
if let Err(error) = archive.add_archive(
cratepath,
Box::new(move |f| {
if f == METADATA_FILENAME {
Some(Box::new(move |f, metadata_link| {
if f == METADATA_FILENAME || f == rmeta_link::FILENAME {
return true;
}

let canonical = f.replace('-', "_");

let is_rust_object =
canonical.starts_with(&canonical_name) && looks_like_rust_object_file(f);
metadata_link.is_some_and(|m| m.rust_object_files.iter().any(|rf| rf == f));

// If we're performing LTO and this is a rust-generated object
// file, then we don't need the object file as it's part of the
Expand All @@ -3203,7 +3230,7 @@ fn add_static_crate(
}

false
}),
})),
) {
sess.dcx()
.emit_fatal(errors::RlibArchiveBuildFailure { path: cratepath.clone(), error });
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/back/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod link;
pub(crate) mod linker;
pub mod lto;
pub mod metadata;
pub mod rmeta_link;
pub(crate) mod rpath;
pub mod symbol_export;
pub mod write;
Expand Down
56 changes: 56 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/rmeta_link.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! Late-metadata archive member that lists which rlib entries are Rust object files,
//! and potentially other data collected and used when building or linking a rlib.
//! See <https://github.com/rust-lang/rust/issues/138243>.

use std::path::Path;

use object::read::archive::ArchiveFile;
use rustc_serialize::opaque::mem_encoder::MemEncoder;
use rustc_serialize::opaque::{MAGIC_END_BYTES, MemDecoder};
use rustc_serialize::{Decodable, Encodable};

use super::metadata::search_for_section;

pub(crate) const FILENAME: &str = "lib.rmeta-link";
pub(crate) const SECTION: &str = ".rmeta-link";

pub struct RmetaLink {
pub rust_object_files: Vec<String>,
}

impl RmetaLink {
pub(crate) fn encode(&self) -> Vec<u8> {
let mut encoder = MemEncoder::new();
self.rust_object_files.encode(&mut encoder);
let mut data = encoder.finish();
data.extend_from_slice(MAGIC_END_BYTES);
data
}

pub(crate) fn decode(data: &[u8]) -> Option<RmetaLink> {
let mut decoder = MemDecoder::new(data, 0).ok()?;
let rust_object_files = Vec::<String>::decode(&mut decoder);
Some(RmetaLink { rust_object_files })
}
}

/// Reads the link-time metadata from an already-parsed archive.
pub fn read(archive: &ArchiveFile<'_>, archive_data: &[u8], rlib_path: &Path) -> Option<RmetaLink> {
for entry in archive.members() {
let entry = entry.ok()?;
if entry.name() == FILENAME.as_bytes() {
let data = entry.data(archive_data).ok()?;
let section_data = search_for_section(rlib_path, data, SECTION).ok()?;
return RmetaLink::decode(section_data);
}
}
None
}

/// Like [`read`], but parses the archive from raw bytes.
///
/// Use this when the caller's `ArchiveFile` comes from a different version of the `object` crate.
pub fn read_from_data(archive_data: &[u8], rlib_path: &Path) -> Option<RmetaLink> {
let archive = ArchiveFile::parse(archive_data).ok()?;
read(&archive, archive_data, rlib_path)
}
19 changes: 1 addition & 18 deletions compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use rustc_middle::util::Providers;
use rustc_serialize::opaque::{FileEncoder, MemDecoder};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_session::Session;
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::config::{CrateType, OutputFilenames, OutputType};
use rustc_session::cstore::{self, CrateSource};
use rustc_session::lint::builtin::LINKER_MESSAGES;
use rustc_span::Symbol;
Expand Down Expand Up @@ -272,23 +272,6 @@ pub fn provide(providers: &mut Providers) {
providers.queries.global_backend_features = |_tcx: TyCtxt<'_>, ()| vec![];
}

/// Checks if the given filename ends with the `.rcgu.o` extension that `rustc`
/// uses for the object files it generates.
pub fn looks_like_rust_object_file(filename: &str) -> bool {
let path = Path::new(filename);
let ext = path.extension().and_then(|s| s.to_str());
if ext != Some(OutputType::Object.extension()) {
// The file name does not end with ".o", so it can't be an object file.
return false;
}

// Strip the ".o" at the end
let ext2 = path.file_stem().and_then(|s| Path::new(s).extension()).and_then(|s| s.to_str());

// Check if the "inner" extension
ext2 == Some(RUST_CGU_EXT)
}

const RLINK_VERSION: u32 = 1;
const RLINK_MAGIC: &[u8] = b"rustlink";

Expand Down
Loading
Loading