Initial support for dynamically linked crates
This commit is contained in:
parent
62c5f58f57
commit
14535312b5
70 changed files with 1536 additions and 119 deletions
|
|
@ -4031,6 +4031,7 @@ dependencies = [
|
|||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"tempfile",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1310,7 +1310,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||
// this as a special case.
|
||||
return self.lower_fn_body(decl, contract, |this| {
|
||||
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) {
|
||||
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
|
||||
|| this.tcx.is_sdylib_interface_build()
|
||||
{
|
||||
let span = this.lower_span(span);
|
||||
let empty_block = hir::Block {
|
||||
hir_id: this.next_id(),
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ struct AstValidator<'a> {
|
|||
|
||||
lint_node_id: NodeId,
|
||||
|
||||
is_sdylib_interface: bool,
|
||||
|
||||
lint_buffer: &'a mut LintBuffer,
|
||||
}
|
||||
|
||||
|
|
@ -952,7 +954,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_defaultness(item.span, *defaultness);
|
||||
|
||||
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
|
||||
if body.is_none() && !is_intrinsic {
|
||||
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
|
||||
self.dcx().emit_err(errors::FnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
|
|
@ -1441,7 +1443,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
});
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||
if body.is_none() {
|
||||
if body.is_none() && !self.is_sdylib_interface {
|
||||
self.dcx().emit_err(errors::AssocFnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
|
|
@ -1689,6 +1691,7 @@ pub fn check_crate(
|
|||
sess: &Session,
|
||||
features: &Features,
|
||||
krate: &Crate,
|
||||
is_sdylib_interface: bool,
|
||||
lints: &mut LintBuffer,
|
||||
) -> bool {
|
||||
let mut validator = AstValidator {
|
||||
|
|
@ -1701,6 +1704,7 @@ pub fn check_crate(
|
|||
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||
extern_mod_safety: None,
|
||||
lint_node_id: CRATE_NODE_ID,
|
||||
is_sdylib_interface,
|
||||
lint_buffer: lints,
|
||||
};
|
||||
visit::walk_crate(&mut validator, krate);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ use std::borrow::Cow;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
|
||||
pub use state::{
|
||||
AnnNode, Comments, PpAnn, PrintState, State, print_crate, print_crate_as_interface,
|
||||
};
|
||||
|
||||
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
|
||||
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ pub struct State<'a> {
|
|||
pub s: pp::Printer,
|
||||
comments: Option<Comments<'a>>,
|
||||
ann: &'a (dyn PpAnn + 'a),
|
||||
is_sdylib_interface: bool,
|
||||
}
|
||||
|
||||
const INDENT_UNIT: isize = 4;
|
||||
|
|
@ -237,9 +238,36 @@ pub fn print_crate<'a>(
|
|||
edition: Edition,
|
||||
g: &AttrIdGenerator,
|
||||
) -> String {
|
||||
let mut s =
|
||||
State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
|
||||
let mut s = State {
|
||||
s: pp::Printer::new(),
|
||||
comments: Some(Comments::new(sm, filename, input)),
|
||||
ann,
|
||||
is_sdylib_interface: false,
|
||||
};
|
||||
|
||||
print_crate_inner(&mut s, krate, is_expanded, edition, g);
|
||||
s.s.eof()
|
||||
}
|
||||
|
||||
pub fn print_crate_as_interface(
|
||||
krate: &ast::Crate,
|
||||
edition: Edition,
|
||||
g: &AttrIdGenerator,
|
||||
) -> String {
|
||||
let mut s =
|
||||
State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: true };
|
||||
|
||||
print_crate_inner(&mut s, krate, false, edition, g);
|
||||
s.s.eof()
|
||||
}
|
||||
|
||||
fn print_crate_inner<'a>(
|
||||
s: &mut State<'a>,
|
||||
krate: &ast::Crate,
|
||||
is_expanded: bool,
|
||||
edition: Edition,
|
||||
g: &AttrIdGenerator,
|
||||
) {
|
||||
// We need to print shebang before anything else
|
||||
// otherwise the resulting code will not compile
|
||||
// and shebang will be useless.
|
||||
|
|
@ -282,8 +310,7 @@ pub fn print_crate<'a>(
|
|||
s.print_item(item);
|
||||
}
|
||||
s.print_remaining_comments();
|
||||
s.ann.post(&mut s, AnnNode::Crate(krate));
|
||||
s.s.eof()
|
||||
s.ann.post(s, AnnNode::Crate(krate));
|
||||
}
|
||||
|
||||
/// Should two consecutive tokens be printed with a space between them?
|
||||
|
|
@ -1111,7 +1138,7 @@ impl<'a> PrintState<'a> for State<'a> {
|
|||
|
||||
impl<'a> State<'a> {
|
||||
pub fn new() -> State<'a> {
|
||||
State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
|
||||
State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: false }
|
||||
}
|
||||
|
||||
fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
|
||||
|
|
|
|||
|
|
@ -160,6 +160,10 @@ impl<'a> State<'a> {
|
|||
|
||||
/// Pretty-prints an item.
|
||||
pub(crate) fn print_item(&mut self, item: &ast::Item) {
|
||||
if self.is_sdylib_interface && item.span.is_dummy() {
|
||||
// Do not print prelude for interface files.
|
||||
return;
|
||||
}
|
||||
self.hardbreak_if_not_bol();
|
||||
self.maybe_print_comment(item.span.lo());
|
||||
self.print_outer_attributes(&item.attrs);
|
||||
|
|
@ -682,6 +686,13 @@ impl<'a> State<'a> {
|
|||
self.print_contract(contract);
|
||||
}
|
||||
if let Some((body, (cb, ib))) = body_cb_ib {
|
||||
if self.is_sdylib_interface {
|
||||
self.word(";");
|
||||
self.end(ib); // end inner head-block
|
||||
self.end(cb); // end outer head-block
|
||||
return;
|
||||
}
|
||||
|
||||
self.nbsp();
|
||||
self.print_block_with_attrs(body, attrs, cb, ib);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,11 @@ use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
|
|||
|
||||
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
|
||||
match crate_type {
|
||||
CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
|
||||
CrateType::Executable
|
||||
| CrateType::Dylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Sdylib => true,
|
||||
CrateType::Rlib | CrateType::ProcMacro => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool {
|
|||
| CrateType::Dylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::ProcMacro => true,
|
||||
| CrateType::ProcMacro
|
||||
| CrateType::Sdylib => true,
|
||||
CrateType::Rlib => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,11 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
|
|||
// in the `.debug_gdb_scripts` section. For that reason, we make sure that the
|
||||
// section is only emitted for leaf crates.
|
||||
let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
|
||||
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => {
|
||||
CrateType::Executable
|
||||
| CrateType::Dylib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Sdylib => {
|
||||
// These are crate types for which we will embed pretty printers since they
|
||||
// are treated as leaf crates.
|
||||
true
|
||||
|
|
|
|||
|
|
@ -1053,9 +1053,10 @@ fn link_natively(
|
|||
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
|
||||
}
|
||||
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
|
||||
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["-x"])
|
||||
}
|
||||
(
|
||||
Strip::Symbols,
|
||||
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib,
|
||||
) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]),
|
||||
(Strip::Symbols, _) => {
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"])
|
||||
}
|
||||
|
|
@ -1243,8 +1244,10 @@ fn add_sanitizer_libraries(
|
|||
// which should be linked to both executables and dynamic libraries.
|
||||
// Everywhere else the runtimes are currently distributed as static
|
||||
// libraries which should be linked to executables only.
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
|
||||
&& !(sess.target.is_like_darwin || sess.target.is_like_msvc)
|
||||
if matches!(
|
||||
crate_type,
|
||||
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib
|
||||
) && !(sess.target.is_like_darwin || sess.target.is_like_msvc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -1938,6 +1941,7 @@ fn add_late_link_args(
|
|||
codegen_results: &CodegenResults,
|
||||
) {
|
||||
let any_dynamic_crate = crate_type == CrateType::Dylib
|
||||
|| crate_type == CrateType::Sdylib
|
||||
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
|
||||
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1817,7 +1817,7 @@ pub(crate) fn linked_symbols(
|
|||
crate_type: CrateType,
|
||||
) -> Vec<(String, SymbolExportKind)> {
|
||||
match crate_type {
|
||||
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
|
||||
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (),
|
||||
CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
|
||||
return Vec::new();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
|
|||
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
|
||||
SymbolExportLevel::C
|
||||
}
|
||||
CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust,
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel {
|
|||
}
|
||||
|
||||
fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<SymbolExportInfo> {
|
||||
if !tcx.sess.opts.output_types.should_codegen() {
|
||||
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ fn exported_symbols_provider_local<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
_: LocalCrate,
|
||||
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
|
||||
if !tcx.sess.opts.output_types.should_codegen() {
|
||||
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
|
||||
return &[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1092,7 +1092,7 @@ impl CrateInfo {
|
|||
}
|
||||
|
||||
let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
|
||||
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
|
||||
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
|
||||
// These are crate types for which we invoke the linker and can embed
|
||||
// NatVis visualizers.
|
||||
true
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ use rustc_metadata::locator;
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_session::config::{
|
||||
CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions,
|
||||
Z_OPTIONS, nightly_options, parse_target_triple,
|
||||
CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType,
|
||||
UnstableOptions, Z_OPTIONS, nightly_options, parse_target_triple,
|
||||
};
|
||||
use rustc_session::getopts::{self, Matches};
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
|
|
@ -352,6 +352,8 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
|
|||
|
||||
passes::write_dep_info(tcx);
|
||||
|
||||
passes::write_interface(tcx);
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
{
|
||||
|
|
@ -816,6 +818,7 @@ fn print_crate_info(
|
|||
let supported_crate_types = CRATE_TYPES
|
||||
.iter()
|
||||
.filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type))
|
||||
.filter(|(_, crate_type)| *crate_type != CrateType::Sdylib)
|
||||
.map(|(crate_type_sym, _)| *crate_type_sym)
|
||||
.collect::<BTreeSet<_>>();
|
||||
for supported_crate_type in supported_crate_types {
|
||||
|
|
|
|||
|
|
@ -536,6 +536,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// Unstable attributes:
|
||||
// ==========================================================================
|
||||
|
||||
// Linking:
|
||||
gated!(
|
||||
export_stable, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, experimental!(export_stable)
|
||||
),
|
||||
|
||||
// Testing:
|
||||
gated!(
|
||||
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
|
||||
|
|
|
|||
|
|
@ -485,6 +485,8 @@ declare_features! (
|
|||
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
|
||||
/// Allows explicit tail calls via `become` expression.
|
||||
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
|
||||
/// Allows using `#[export_stable]` which indicates that an item is exportable.
|
||||
(incomplete, export_stable, "CURRENT_RUSTC_VERSION", Some(139939)),
|
||||
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
|
||||
/// for functions with varargs.
|
||||
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
|
||||
|
|
|
|||
|
|
@ -31,10 +31,11 @@ use rustc_resolve::Resolver;
|
|||
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||
use rustc_session::cstore::Untracked;
|
||||
use rustc_session::output::{collect_crate_types, filename_for_input};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::{
|
||||
ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
|
||||
DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
|
||||
};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use rustc_trait_selection::traits;
|
||||
|
|
@ -237,6 +238,7 @@ fn configure_and_expand(
|
|||
sess,
|
||||
features,
|
||||
&krate,
|
||||
tcx.is_sdylib_interface_build(),
|
||||
resolver.lint_buffer(),
|
||||
)
|
||||
});
|
||||
|
|
@ -253,6 +255,9 @@ fn configure_and_expand(
|
|||
sess.dcx().emit_err(errors::MixedProcMacroCrate);
|
||||
}
|
||||
}
|
||||
if crate_types.contains(&CrateType::Sdylib) && !tcx.features().export_stable() {
|
||||
feature_err(sess, sym::export_stable, DUMMY_SP, "`sdylib` crate type is unstable").emit();
|
||||
}
|
||||
|
||||
if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
|
||||
sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort);
|
||||
|
|
@ -742,6 +747,25 @@ pub fn write_dep_info(tcx: TyCtxt<'_>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
if !tcx.crate_types().contains(&rustc_session::config::CrateType::Sdylib) {
|
||||
return;
|
||||
}
|
||||
let _timer = tcx.sess.timer("write_interface");
|
||||
let (_, krate) = &*tcx.resolver_for_lowering().borrow();
|
||||
|
||||
let krate = rustc_ast_pretty::pprust::print_crate_as_interface(
|
||||
krate,
|
||||
tcx.sess.psess.edition,
|
||||
&tcx.sess.psess.attr_id_generator,
|
||||
);
|
||||
let export_output = tcx.output_filenames(()).interface_path();
|
||||
let mut file = fs::File::create_buffered(export_output).unwrap();
|
||||
if let Err(err) = write!(file, "{}", krate) {
|
||||
tcx.dcx().fatal(format!("error writing interface file: {}", err));
|
||||
}
|
||||
}
|
||||
|
||||
pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
|
||||
let providers = &mut Providers::default();
|
||||
providers.analysis = analysis;
|
||||
|
|
@ -930,6 +954,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
CStore::from_tcx(tcx).report_unused_deps(tcx);
|
||||
},
|
||||
{
|
||||
tcx.ensure_ok().exportable_items(LOCAL_CRATE);
|
||||
tcx.ensure_ok().stable_order_of_exportable_impls(LOCAL_CRATE);
|
||||
tcx.par_hir_for_each_module(|module| {
|
||||
tcx.ensure_ok().check_mod_loops(module);
|
||||
tcx.ensure_ok().check_mod_attrs(module);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ rustc_serialize = { path = "../rustc_serialize" }
|
|||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
tempfile = "3.7.1"
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
|
|||
writeln!(fmt, " hash: {}", data.hash())?;
|
||||
writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
|
||||
writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
|
||||
let CrateSource { dylib, rlib, rmeta } = data.source();
|
||||
let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();
|
||||
if let Some(dylib) = dylib {
|
||||
writeln!(fmt, " dylib: {}", dylib.0.display())?;
|
||||
}
|
||||
|
|
@ -158,6 +158,9 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
|
|||
if let Some(rmeta) = rmeta {
|
||||
writeln!(fmt, " rmeta: {}", rmeta.0.display())?;
|
||||
}
|
||||
if let Some(sdylib_interface) = sdylib_interface {
|
||||
writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,45 +88,42 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
return IndexVec::new();
|
||||
}
|
||||
|
||||
let preferred_linkage = match ty {
|
||||
// Generating a dylib without `-C prefer-dynamic` means that we're going
|
||||
// to try to eagerly statically link all dependencies. This is normally
|
||||
// done for end-product dylibs, not intermediate products.
|
||||
//
|
||||
// Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set,
|
||||
// the caller may be code-size conscious, but without it, it makes sense
|
||||
// to statically link a cdylib or staticlib. For staticlibs we use
|
||||
// `-Z staticlib-prefer-dynamic` for now. This may be merged into
|
||||
// `-C prefer-dynamic` in the future.
|
||||
CrateType::Dylib | CrateType::Cdylib => {
|
||||
if sess.opts.cg.prefer_dynamic {
|
||||
Linkage::Dynamic
|
||||
} else {
|
||||
let preferred_linkage =
|
||||
match ty {
|
||||
// Generating a dylib without `-C prefer-dynamic` means that we're going
|
||||
// to try to eagerly statically link all dependencies. This is normally
|
||||
// done for end-product dylibs, not intermediate products.
|
||||
//
|
||||
// Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set,
|
||||
// the caller may be code-size conscious, but without it, it makes sense
|
||||
// to statically link a cdylib or staticlib. For staticlibs we use
|
||||
// `-Z staticlib-prefer-dynamic` for now. This may be merged into
|
||||
// `-C prefer-dynamic` in the future.
|
||||
CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
|
||||
if sess.opts.cg.prefer_dynamic { Linkage::Dynamic } else { Linkage::Static }
|
||||
}
|
||||
CrateType::Staticlib => {
|
||||
if sess.opts.unstable_opts.staticlib_prefer_dynamic {
|
||||
Linkage::Dynamic
|
||||
} else {
|
||||
Linkage::Static
|
||||
}
|
||||
}
|
||||
|
||||
// If the global prefer_dynamic switch is turned off, or the final
|
||||
// executable will be statically linked, prefer static crate linkage.
|
||||
CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => {
|
||||
Linkage::Static
|
||||
}
|
||||
}
|
||||
CrateType::Staticlib => {
|
||||
if sess.opts.unstable_opts.staticlib_prefer_dynamic {
|
||||
Linkage::Dynamic
|
||||
} else {
|
||||
Linkage::Static
|
||||
}
|
||||
}
|
||||
CrateType::Executable => Linkage::Dynamic,
|
||||
|
||||
// If the global prefer_dynamic switch is turned off, or the final
|
||||
// executable will be statically linked, prefer static crate linkage.
|
||||
CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => {
|
||||
Linkage::Static
|
||||
}
|
||||
CrateType::Executable => Linkage::Dynamic,
|
||||
// proc-macro crates are mostly cdylibs, but we also need metadata.
|
||||
CrateType::ProcMacro => Linkage::Static,
|
||||
|
||||
// proc-macro crates are mostly cdylibs, but we also need metadata.
|
||||
CrateType::ProcMacro => Linkage::Static,
|
||||
|
||||
// No linkage happens with rlibs, we just needed the metadata (which we
|
||||
// got long ago), so don't bother with anything.
|
||||
CrateType::Rlib => Linkage::NotLinked,
|
||||
};
|
||||
// No linkage happens with rlibs, we just needed the metadata (which we
|
||||
// got long ago), so don't bother with anything.
|
||||
CrateType::Rlib => Linkage::NotLinked,
|
||||
};
|
||||
|
||||
let mut unavailable_as_static = Vec::new();
|
||||
|
||||
|
|
@ -165,7 +162,9 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
|
||||
let all_dylibs = || {
|
||||
tcx.crates(()).iter().filter(|&&cnum| {
|
||||
!tcx.dep_kind(cnum).macros_only() && tcx.used_crate_source(cnum).dylib.is_some()
|
||||
!tcx.dep_kind(cnum).macros_only()
|
||||
&& (tcx.used_crate_source(cnum).dylib.is_some()
|
||||
|| tcx.used_crate_source(cnum).sdylib_interface.is_some())
|
||||
})
|
||||
};
|
||||
|
||||
|
|
@ -273,7 +272,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
match *kind {
|
||||
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
|
||||
Linkage::Static if src.rlib.is_some() => continue,
|
||||
Linkage::Dynamic if src.dylib.is_some() => continue,
|
||||
Linkage::Dynamic if src.dylib.is_some() || src.sdylib_interface.is_some() => continue,
|
||||
kind => {
|
||||
let kind = match kind {
|
||||
Linkage::Static => "rlib",
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ use std::{cmp, fmt};
|
|||
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::owned_slice::slice_owned;
|
||||
use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_errors::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
|
|
@ -231,6 +231,7 @@ use rustc_session::search_paths::PathKind;
|
|||
use rustc_session::utils::CanonicalizedPath;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::{Target, TargetTuple};
|
||||
use tempfile::Builder as TempFileBuilder;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::creader::{Library, MetadataLoader};
|
||||
|
|
@ -277,6 +278,7 @@ pub(crate) enum CrateFlavor {
|
|||
Rlib,
|
||||
Rmeta,
|
||||
Dylib,
|
||||
SDylib,
|
||||
}
|
||||
|
||||
impl fmt::Display for CrateFlavor {
|
||||
|
|
@ -285,6 +287,7 @@ impl fmt::Display for CrateFlavor {
|
|||
CrateFlavor::Rlib => "rlib",
|
||||
CrateFlavor::Rmeta => "rmeta",
|
||||
CrateFlavor::Dylib => "dylib",
|
||||
CrateFlavor::SDylib => "sdylib",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -295,6 +298,7 @@ impl IntoDiagArg for CrateFlavor {
|
|||
CrateFlavor::Rlib => DiagArgValue::Str(Cow::Borrowed("rlib")),
|
||||
CrateFlavor::Rmeta => DiagArgValue::Str(Cow::Borrowed("rmeta")),
|
||||
CrateFlavor::Dylib => DiagArgValue::Str(Cow::Borrowed("dylib")),
|
||||
CrateFlavor::SDylib => DiagArgValue::Str(Cow::Borrowed("sdylib")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -379,14 +383,18 @@ impl<'a> CrateLocator<'a> {
|
|||
&format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
|
||||
let staticlib_prefix =
|
||||
&format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
|
||||
let interface_prefix = rmeta_prefix;
|
||||
|
||||
let rmeta_suffix = ".rmeta";
|
||||
let rlib_suffix = ".rlib";
|
||||
let dylib_suffix = &self.target.dll_suffix;
|
||||
let staticlib_suffix = &self.target.staticlib_suffix;
|
||||
let interface_suffix = ".rs";
|
||||
|
||||
let mut candidates: FxIndexMap<_, (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>)> =
|
||||
Default::default();
|
||||
let mut candidates: FxIndexMap<
|
||||
_,
|
||||
(FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>),
|
||||
> = Default::default();
|
||||
|
||||
// First, find all possible candidate rlibs and dylibs purely based on
|
||||
// the name of the files themselves. We're trying to match against an
|
||||
|
|
@ -417,6 +425,7 @@ impl<'a> CrateLocator<'a> {
|
|||
(rlib_prefix.as_str(), rlib_suffix, CrateFlavor::Rlib),
|
||||
(rmeta_prefix.as_str(), rmeta_suffix, CrateFlavor::Rmeta),
|
||||
(dylib_prefix, dylib_suffix, CrateFlavor::Dylib),
|
||||
(interface_prefix, interface_suffix, CrateFlavor::SDylib),
|
||||
] {
|
||||
if prefix == staticlib_prefix && suffix == staticlib_suffix {
|
||||
should_check_staticlibs = false;
|
||||
|
|
@ -425,7 +434,7 @@ impl<'a> CrateLocator<'a> {
|
|||
for (hash, spf) in matches {
|
||||
info!("lib candidate: {}", spf.path.display());
|
||||
|
||||
let (rlibs, rmetas, dylibs) =
|
||||
let (rlibs, rmetas, dylibs, interfaces) =
|
||||
candidates.entry(hash.to_string()).or_default();
|
||||
{
|
||||
// As a perforamnce optimisation we canonicalize the path and skip
|
||||
|
|
@ -446,6 +455,7 @@ impl<'a> CrateLocator<'a> {
|
|||
CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
|
||||
CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
|
||||
CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
|
||||
CrateFlavor::SDylib => interfaces.insert(path, search_path.kind),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -472,8 +482,8 @@ impl<'a> CrateLocator<'a> {
|
|||
// libraries corresponds to the crate id and hash criteria that this
|
||||
// search is being performed for.
|
||||
let mut libraries = FxIndexMap::default();
|
||||
for (_hash, (rlibs, rmetas, dylibs)) in candidates {
|
||||
if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
|
||||
for (_hash, (rlibs, rmetas, dylibs, interfaces)) in candidates {
|
||||
if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs, interfaces)? {
|
||||
libraries.insert(svh, lib);
|
||||
}
|
||||
}
|
||||
|
|
@ -508,6 +518,7 @@ impl<'a> CrateLocator<'a> {
|
|||
rlibs: FxIndexMap<PathBuf, PathKind>,
|
||||
rmetas: FxIndexMap<PathBuf, PathKind>,
|
||||
dylibs: FxIndexMap<PathBuf, PathKind>,
|
||||
interfaces: FxIndexMap<PathBuf, PathKind>,
|
||||
) -> Result<Option<(Svh, Library)>, CrateError> {
|
||||
let mut slot = None;
|
||||
// Order here matters, rmeta should come first.
|
||||
|
|
@ -515,12 +526,17 @@ impl<'a> CrateLocator<'a> {
|
|||
// Make sure there's at most one rlib and at most one dylib.
|
||||
//
|
||||
// See comment in `extract_one` below.
|
||||
let source = CrateSource {
|
||||
rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
|
||||
rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
|
||||
dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?,
|
||||
};
|
||||
Ok(slot.map(|(svh, metadata, _)| (svh, Library { source, metadata })))
|
||||
let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?;
|
||||
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?;
|
||||
let sdylib_interface = self.extract_one(interfaces, CrateFlavor::SDylib, &mut slot)?;
|
||||
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?;
|
||||
|
||||
if sdylib_interface.is_some() && dylib.is_none() {
|
||||
return Err(CrateError::FullMetadataNotFound(self.crate_name, CrateFlavor::SDylib));
|
||||
}
|
||||
|
||||
let source = CrateSource { rmeta, rlib, dylib, sdylib_interface };
|
||||
Ok(slot.map(|(svh, metadata, _, _)| (svh, Library { source, metadata })))
|
||||
}
|
||||
|
||||
fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
|
||||
|
|
@ -550,7 +566,7 @@ impl<'a> CrateLocator<'a> {
|
|||
&mut self,
|
||||
m: FxIndexMap<PathBuf, PathKind>,
|
||||
flavor: CrateFlavor,
|
||||
slot: &mut Option<(Svh, MetadataBlob, PathBuf)>,
|
||||
slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>,
|
||||
) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
|
||||
// If we are producing an rlib, and we've already loaded metadata, then
|
||||
// we should not attempt to discover further crate sources (unless we're
|
||||
|
|
@ -586,6 +602,7 @@ impl<'a> CrateLocator<'a> {
|
|||
&lib,
|
||||
self.metadata_loader,
|
||||
self.cfg_version,
|
||||
Some(self.crate_name),
|
||||
) {
|
||||
Ok(blob) => {
|
||||
if let Some(h) = self.crate_matches(&blob, &lib) {
|
||||
|
|
@ -610,6 +627,11 @@ impl<'a> CrateLocator<'a> {
|
|||
}
|
||||
Err(MetadataError::LoadFailure(err)) => {
|
||||
info!("no metadata found: {}", err);
|
||||
// Metadata was loaded from interface file earlier.
|
||||
if let Some((.., CrateFlavor::SDylib)) = slot {
|
||||
ret = Some((lib, kind));
|
||||
continue;
|
||||
}
|
||||
// The file was present and created by the same compiler version, but we
|
||||
// couldn't load it for some reason. Give a hard error instead of silently
|
||||
// ignoring it, but only if we would have given an error anyway.
|
||||
|
|
@ -679,7 +701,7 @@ impl<'a> CrateLocator<'a> {
|
|||
return Err(CrateError::FullMetadataNotFound(self.crate_name, flavor));
|
||||
}
|
||||
} else {
|
||||
*slot = Some((hash, metadata, lib.clone()));
|
||||
*slot = Some((hash, metadata, lib.clone(), flavor));
|
||||
}
|
||||
ret = Some((lib, kind));
|
||||
}
|
||||
|
|
@ -736,6 +758,7 @@ impl<'a> CrateLocator<'a> {
|
|||
let mut rlibs = FxIndexMap::default();
|
||||
let mut rmetas = FxIndexMap::default();
|
||||
let mut dylibs = FxIndexMap::default();
|
||||
let mut sdylib_interfaces = FxIndexMap::default();
|
||||
for loc in &self.exact_paths {
|
||||
let loc_canon = loc.canonicalized();
|
||||
let loc_orig = loc.original();
|
||||
|
|
@ -763,6 +786,9 @@ impl<'a> CrateLocator<'a> {
|
|||
rmetas.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||
continue;
|
||||
}
|
||||
if file.ends_with(".rs") {
|
||||
sdylib_interfaces.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||
}
|
||||
}
|
||||
let dll_prefix = self.target.dll_prefix.as_ref();
|
||||
let dll_suffix = self.target.dll_suffix.as_ref();
|
||||
|
|
@ -776,7 +802,8 @@ impl<'a> CrateLocator<'a> {
|
|||
}
|
||||
|
||||
// Extract the dylib/rlib/rmeta triple.
|
||||
self.extract_lib(rlibs, rmetas, dylibs).map(|opt| opt.map(|(_, lib)| lib))
|
||||
self.extract_lib(rlibs, rmetas, dylibs, sdylib_interfaces)
|
||||
.map(|opt| opt.map(|(_, lib)| lib))
|
||||
}
|
||||
|
||||
pub(crate) fn into_error(self, dep_root: Option<CratePaths>) -> CrateError {
|
||||
|
|
@ -797,6 +824,7 @@ fn get_metadata_section<'p>(
|
|||
filename: &'p Path,
|
||||
loader: &dyn MetadataLoader,
|
||||
cfg_version: &'static str,
|
||||
crate_name: Option<Symbol>,
|
||||
) -> Result<MetadataBlob, MetadataError<'p>> {
|
||||
if !filename.exists() {
|
||||
return Err(MetadataError::NotPresent(filename));
|
||||
|
|
@ -805,6 +833,55 @@ fn get_metadata_section<'p>(
|
|||
CrateFlavor::Rlib => {
|
||||
loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
|
||||
}
|
||||
CrateFlavor::SDylib => {
|
||||
let compiler = std::env::current_exe().map_err(|_err| {
|
||||
MetadataError::LoadFailure(
|
||||
"couldn't obtain current compiler binary when loading sdylib interface"
|
||||
.to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let tmp_path = match TempFileBuilder::new().prefix("rustc").tempdir() {
|
||||
Ok(tmp_path) => tmp_path,
|
||||
Err(error) => {
|
||||
return Err(MetadataError::LoadFailure(format!(
|
||||
"couldn't create a temp dir: {}",
|
||||
error
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
let crate_name = crate_name.unwrap();
|
||||
debug!("compiling {}", filename.display());
|
||||
// FIXME: This will need to be done either within the current compiler session or
|
||||
// as a separate compiler session in the same process.
|
||||
let res = std::process::Command::new(compiler)
|
||||
.arg(&filename)
|
||||
.arg("--emit=metadata")
|
||||
.arg(format!("--crate-name={}", crate_name))
|
||||
.arg(format!("--out-dir={}", tmp_path.path().display()))
|
||||
.arg("-Zbuild-sdylib-interface")
|
||||
.output()
|
||||
.map_err(|err| {
|
||||
MetadataError::LoadFailure(format!("couldn't compile interface: {}", err))
|
||||
})?;
|
||||
|
||||
if !res.status.success() {
|
||||
return Err(MetadataError::LoadFailure(format!(
|
||||
"couldn't compile interface: {}",
|
||||
std::str::from_utf8(&res.stderr).unwrap_or_default()
|
||||
)));
|
||||
}
|
||||
|
||||
// Load interface metadata instead of crate metadata.
|
||||
let interface_metadata_name = format!("lib{}.rmeta", crate_name);
|
||||
let rmeta_file = tmp_path.path().join(interface_metadata_name);
|
||||
debug!("loading interface metadata from {}", rmeta_file.display());
|
||||
let rmeta = get_rmeta_metadata_section(&rmeta_file)?;
|
||||
let _ = std::fs::remove_file(rmeta_file);
|
||||
|
||||
rmeta
|
||||
}
|
||||
CrateFlavor::Dylib => {
|
||||
let buf =
|
||||
loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
|
||||
|
|
@ -834,24 +911,7 @@ fn get_metadata_section<'p>(
|
|||
// Header is okay -> inflate the actual metadata
|
||||
buf.slice(|buf| &buf[data_start..(data_start + metadata_len)])
|
||||
}
|
||||
CrateFlavor::Rmeta => {
|
||||
// mmap the file, because only a small fraction of it is read.
|
||||
let file = std::fs::File::open(filename).map_err(|_| {
|
||||
MetadataError::LoadFailure(format!(
|
||||
"failed to open rmeta metadata: '{}'",
|
||||
filename.display()
|
||||
))
|
||||
})?;
|
||||
let mmap = unsafe { Mmap::map(file) };
|
||||
let mmap = mmap.map_err(|_| {
|
||||
MetadataError::LoadFailure(format!(
|
||||
"failed to mmap rmeta metadata: '{}'",
|
||||
filename.display()
|
||||
))
|
||||
})?;
|
||||
|
||||
slice_owned(mmap, Deref::deref)
|
||||
}
|
||||
CrateFlavor::Rmeta => get_rmeta_metadata_section(filename)?,
|
||||
};
|
||||
let Ok(blob) = MetadataBlob::new(raw_bytes) else {
|
||||
return Err(MetadataError::LoadFailure(format!(
|
||||
|
|
@ -877,6 +937,25 @@ fn get_metadata_section<'p>(
|
|||
}
|
||||
}
|
||||
|
||||
fn get_rmeta_metadata_section<'a, 'p>(filename: &'p Path) -> Result<OwnedSlice, MetadataError<'a>> {
|
||||
// mmap the file, because only a small fraction of it is read.
|
||||
let file = std::fs::File::open(filename).map_err(|_| {
|
||||
MetadataError::LoadFailure(format!(
|
||||
"failed to open rmeta metadata: '{}'",
|
||||
filename.display()
|
||||
))
|
||||
})?;
|
||||
let mmap = unsafe { Mmap::map(file) };
|
||||
let mmap = mmap.map_err(|_| {
|
||||
MetadataError::LoadFailure(format!(
|
||||
"failed to mmap rmeta metadata: '{}'",
|
||||
filename.display()
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(slice_owned(mmap, Deref::deref))
|
||||
}
|
||||
|
||||
/// A diagnostic function for dumping crate metadata to an output stream.
|
||||
pub fn list_file_metadata(
|
||||
target: &Target,
|
||||
|
|
@ -887,7 +966,7 @@ pub fn list_file_metadata(
|
|||
cfg_version: &'static str,
|
||||
) -> IoResult<()> {
|
||||
let flavor = get_flavor_from_path(path);
|
||||
match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
|
||||
match get_metadata_section(target, flavor, path, metadata_loader, cfg_version, None) {
|
||||
Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
|
||||
Err(msg) => write!(out, "{msg}\n"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1489,6 +1489,17 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
|
||||
}
|
||||
|
||||
fn get_exportable_items(self) -> impl Iterator<Item = DefId> {
|
||||
self.root.exportable_items.decode(self).map(move |index| self.local_def_id(index))
|
||||
}
|
||||
|
||||
fn get_stable_order_of_exportable_impls(self) -> impl Iterator<Item = (DefId, usize)> {
|
||||
self.root
|
||||
.stable_order_of_exportable_impls
|
||||
.decode(self)
|
||||
.map(move |v| (self.local_def_id(v.0), v.1))
|
||||
}
|
||||
|
||||
fn exported_symbols<'tcx>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -406,6 +406,8 @@ provide! { tcx, def_id, other, cdata,
|
|||
used_crate_source => { Arc::clone(&cdata.source) }
|
||||
debugger_visualizers => { cdata.get_debugger_visualizers() }
|
||||
|
||||
exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items()) }
|
||||
stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls().collect()) }
|
||||
exported_symbols => {
|
||||
let syms = cdata.exported_symbols(tcx);
|
||||
|
||||
|
|
|
|||
|
|
@ -673,6 +673,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
let debugger_visualizers =
|
||||
stat!("debugger-visualizers", || self.encode_debugger_visualizers());
|
||||
|
||||
let exportable_items = stat!("exportable-items", || self.encode_exportable_items());
|
||||
|
||||
let stable_order_of_exportable_impls =
|
||||
stat!("exportable-items", || self.encode_stable_order_of_exportable_impls());
|
||||
|
||||
// Encode exported symbols info. This is prefetched in `encode_metadata`.
|
||||
let exported_symbols = stat!("exported-symbols", || {
|
||||
self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE))
|
||||
|
|
@ -740,6 +745,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
traits,
|
||||
impls,
|
||||
incoherent_impls,
|
||||
exportable_items,
|
||||
stable_order_of_exportable_impls,
|
||||
exported_symbols,
|
||||
interpret_alloc_index,
|
||||
tables,
|
||||
|
|
@ -2149,6 +2156,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
self.lazy_array(&all_impls)
|
||||
}
|
||||
|
||||
fn encode_exportable_items(&mut self) -> LazyArray<DefIndex> {
|
||||
empty_proc_macro!(self);
|
||||
self.lazy_array(self.tcx.exportable_items(LOCAL_CRATE).iter().map(|def_id| def_id.index))
|
||||
}
|
||||
|
||||
fn encode_stable_order_of_exportable_impls(&mut self) -> LazyArray<(DefIndex, usize)> {
|
||||
empty_proc_macro!(self);
|
||||
let stable_order_of_exportable_impls =
|
||||
self.tcx.stable_order_of_exportable_impls(LOCAL_CRATE);
|
||||
self.lazy_array(
|
||||
stable_order_of_exportable_impls.iter().map(|(def_id, idx)| (def_id.index, *idx)),
|
||||
)
|
||||
}
|
||||
|
||||
// Encodes all symbols exported from this crate into the metadata.
|
||||
//
|
||||
// This pass is seeded off the reachability list calculated in the
|
||||
|
|
|
|||
|
|
@ -280,6 +280,8 @@ pub(crate) struct CrateRoot {
|
|||
tables: LazyTables,
|
||||
debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
|
||||
|
||||
exportable_items: LazyArray<DefIndex>,
|
||||
stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>,
|
||||
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
|
||||
|
||||
syntax_contexts: SyntaxContextTable,
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ macro_rules! arena_types {
|
|||
[] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
|
||||
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
|
||||
[] valtree: rustc_middle::ty::ValTreeKind<'tcx>,
|
||||
[] stable_order_of_exportable_impls:
|
||||
rustc_data_structures::fx::FxIndexMap<rustc_hir::def_id::DefId, usize>,
|
||||
|
||||
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
||||
// since we need to allocate this type on both the `rustc_hir` arena
|
||||
|
|
|
|||
|
|
@ -2239,6 +2239,16 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
query stable_order_of_exportable_impls(_: CrateNum) -> &'tcx FxIndexMap<DefId, usize> {
|
||||
desc { "fetching the stable impl's order" }
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
query exportable_items(_: CrateNum) -> &'tcx [DefId] {
|
||||
desc { "fetching all exportable items in a crate" }
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// The list of symbols exported from the given crate.
|
||||
///
|
||||
/// - All names contained in `exported_symbols(cnum)` are guaranteed to
|
||||
|
|
|
|||
|
|
@ -1828,9 +1828,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.crate_types()
|
||||
.iter()
|
||||
.map(|ty| match *ty {
|
||||
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => {
|
||||
MetadataKind::None
|
||||
}
|
||||
CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Sdylib => MetadataKind::None,
|
||||
CrateType::Rlib => MetadataKind::Uncompressed,
|
||||
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
|
||||
})
|
||||
|
|
@ -2133,7 +2134,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
| CrateType::ProcMacro
|
||||
| CrateType::Cdylib => false,
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Sdylib => false,
|
||||
|
||||
// FIXME rust-lang/rust#64319, rust-lang/rust#64872:
|
||||
// We want to block export of generics from dylibs,
|
||||
|
|
@ -3315,6 +3317,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
&& self.impl_trait_header(def_id).unwrap().constness == hir::Constness::Const
|
||||
}
|
||||
|
||||
pub fn is_sdylib_interface_build(self) -> bool {
|
||||
self.sess.opts.unstable_opts.build_sdylib_interface
|
||||
}
|
||||
|
||||
pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {
|
||||
match self.def_kind(def_id) {
|
||||
DefKind::Fn | DefKind::AssocFn => {}
|
||||
|
|
|
|||
|
|
@ -1978,6 +1978,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn is_exportable(self, def_id: DefId) -> bool {
|
||||
self.exportable_items(def_id.krate).contains(&def_id)
|
||||
}
|
||||
|
||||
/// Check if the given `DefId` is `#\[automatically_derived\]`, *and*
|
||||
/// whether it was produced by expanding a builtin derive macro.
|
||||
pub fn is_builtin_derived(self, def_id: DefId) -> bool {
|
||||
|
|
|
|||
|
|
@ -998,7 +998,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.source_scope = source_scope;
|
||||
}
|
||||
|
||||
if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) {
|
||||
if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden)
|
||||
|| self.tcx.is_sdylib_interface_build()
|
||||
{
|
||||
let source_info = self.source_info(rustc_span::DUMMY_SP);
|
||||
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
|
||||
self.cfg.start_new_block().unit()
|
||||
|
|
|
|||
|
|
@ -356,6 +356,8 @@ passes_ignored_derived_impls =
|
|||
passes_implied_feature_not_exist =
|
||||
feature `{$implied_by}` implying `{$feature}` does not exist
|
||||
|
||||
passes_incorrect_crate_type = lang items are not allowed in stable dylibs
|
||||
|
||||
passes_incorrect_do_not_recommend_args =
|
||||
`#[diagnostic::do_not_recommend]` does not expect any arguments
|
||||
|
||||
|
|
@ -742,6 +744,23 @@ passes_trait_impl_const_stable =
|
|||
passes_transparent_incompatible =
|
||||
transparent {$target} cannot have other repr hints
|
||||
|
||||
passes_unexportable_adt_with_private_fields = ADT types with private fields are not exportable
|
||||
.note = `{$field_name}` is private
|
||||
|
||||
passes_unexportable_fn_abi = only functions with "C" ABI are exportable
|
||||
|
||||
passes_unexportable_generic_fn = generic functions are not exportable
|
||||
|
||||
passes_unexportable_item = {$descr}'s are not exportable
|
||||
|
||||
passes_unexportable_priv_item = private items are not exportable
|
||||
.note = is only usable at visibility `{$vis_descr}`
|
||||
|
||||
passes_unexportable_type_in_interface = {$desc} with `#[export_stable]` attribute uses type `{$ty}`, which is not exportable
|
||||
.label = not exportable
|
||||
|
||||
passes_unexportable_type_repr = types with unstable layout are not exportable
|
||||
|
||||
passes_unknown_external_lang_item =
|
||||
unknown external lang item: `{$lang_item}`
|
||||
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| sym::cfg_attr
|
||||
| sym::cfg_trace
|
||||
| sym::cfg_attr_trace
|
||||
| sym::export_stable // handled in `check_export`
|
||||
// need to be fixed
|
||||
| sym::cfi_encoding // FIXME(cfi_encoding)
|
||||
| sym::pointee // FIXME(derive_coerce_pointee)
|
||||
|
|
|
|||
398
compiler/rustc_passes/src/check_export.rs
Normal file
398
compiler/rustc_passes/src/check_export.rs
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::privacy::{EffectiveVisibility, Level};
|
||||
use rustc_middle::query::{LocalCrate, Providers};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Visibility,
|
||||
};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
use crate::errors::UnexportableItem;
|
||||
|
||||
struct ExportableItemCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
exportable_items: FxIndexSet<DefId>,
|
||||
in_exportable_mod: bool,
|
||||
seen_exportable_in_mod: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> ExportableItemCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> ExportableItemCollector<'tcx> {
|
||||
ExportableItemCollector {
|
||||
tcx,
|
||||
exportable_items: Default::default(),
|
||||
in_exportable_mod: false,
|
||||
seen_exportable_in_mod: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn report_wrong_site(&self, def_id: LocalDefId) {
|
||||
let def_descr = self.tcx.def_descr(def_id.to_def_id());
|
||||
self.tcx.dcx().emit_err(UnexportableItem::Item {
|
||||
descr: &format!("{}", def_descr),
|
||||
span: self.tcx.def_span(def_id),
|
||||
});
|
||||
}
|
||||
|
||||
fn item_is_exportable(&self, def_id: LocalDefId) -> bool {
|
||||
let has_attr = self.tcx.has_attr(def_id, sym::export_stable);
|
||||
if !self.in_exportable_mod && !has_attr {
|
||||
return false;
|
||||
}
|
||||
|
||||
let visibilities = self.tcx.effective_visibilities(());
|
||||
let is_pub = visibilities.is_directly_public(def_id);
|
||||
|
||||
if has_attr && !is_pub {
|
||||
let vis = visibilities.effective_vis(def_id).cloned().unwrap_or(
|
||||
EffectiveVisibility::from_vis(Visibility::Restricted(
|
||||
self.tcx.parent_module_from_def_id(def_id).to_local_def_id(),
|
||||
)),
|
||||
);
|
||||
let vis = vis.at_level(Level::Direct);
|
||||
let span = self.tcx.def_span(def_id);
|
||||
|
||||
self.tcx.dcx().emit_err(UnexportableItem::PrivItem {
|
||||
vis_note: span,
|
||||
vis_descr: &vis.to_string(def_id, self.tcx),
|
||||
span,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
is_pub && (has_attr || self.in_exportable_mod)
|
||||
}
|
||||
|
||||
fn add_exportable(&mut self, def_id: LocalDefId) {
|
||||
self.seen_exportable_in_mod = true;
|
||||
self.exportable_items.insert(def_id.to_def_id());
|
||||
}
|
||||
|
||||
fn walk_item_with_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
let def_id = item.hir_id().owner.def_id;
|
||||
let old_exportable_mod = self.in_exportable_mod;
|
||||
if self.tcx.get_attr(def_id, sym::export_stable).is_some() {
|
||||
self.in_exportable_mod = true;
|
||||
}
|
||||
let old_seen_exportable_in_mod = std::mem::replace(&mut self.seen_exportable_in_mod, false);
|
||||
|
||||
intravisit::walk_item(self, item);
|
||||
|
||||
if self.seen_exportable_in_mod || self.in_exportable_mod {
|
||||
self.exportable_items.insert(def_id.to_def_id());
|
||||
}
|
||||
|
||||
self.seen_exportable_in_mod = old_seen_exportable_in_mod;
|
||||
self.in_exportable_mod = old_exportable_mod;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ExportableItemCollector<'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
let def_id = item.hir_id().owner.def_id;
|
||||
// Applying #[extern] attribute to modules is simply equivalent to
|
||||
// applying the attribute to every public item within it.
|
||||
match item.kind {
|
||||
hir::ItemKind::Mod(..) => {
|
||||
self.walk_item_with_mod(item);
|
||||
return;
|
||||
}
|
||||
hir::ItemKind::Impl(impl_) if impl_.of_trait.is_none() => {
|
||||
self.walk_item_with_mod(item);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !self.item_is_exportable(def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
match item.kind {
|
||||
hir::ItemKind::Fn { .. }
|
||||
| hir::ItemKind::Struct(..)
|
||||
| hir::ItemKind::Enum(..)
|
||||
| hir::ItemKind::Union(..)
|
||||
| hir::ItemKind::TyAlias(..) => {
|
||||
self.add_exportable(def_id);
|
||||
}
|
||||
hir::ItemKind::Use(path, _) => {
|
||||
for res in &path.res {
|
||||
// Only local items are exportable.
|
||||
if let Some(res_id) = res.opt_def_id()
|
||||
&& let Some(res_id) = res_id.as_local()
|
||||
{
|
||||
self.add_exportable(res_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// handled above
|
||||
hir::ItemKind::Mod(..) => unreachable!(),
|
||||
hir::ItemKind::Impl(impl_) if impl_.of_trait.is_none() => {
|
||||
unreachable!();
|
||||
}
|
||||
_ => self.report_wrong_site(def_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
|
||||
let def_id = item.hir_id().owner.def_id;
|
||||
if !self.item_is_exportable(def_id) {
|
||||
return;
|
||||
}
|
||||
match item.kind {
|
||||
hir::ImplItemKind::Fn(..) | hir::ImplItemKind::Type(..) => {
|
||||
self.add_exportable(def_id);
|
||||
}
|
||||
_ => self.report_wrong_site(def_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
|
||||
let def_id = item.hir_id().owner.def_id;
|
||||
if !self.item_is_exportable(def_id) {
|
||||
self.report_wrong_site(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
|
||||
let def_id = item.hir_id().owner.def_id;
|
||||
if !self.item_is_exportable(def_id) {
|
||||
self.report_wrong_site(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ExportableItemsChecker<'tcx, 'a> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
exportable_items: &'a FxIndexSet<DefId>,
|
||||
item_id: DefId,
|
||||
}
|
||||
|
||||
impl<'tcx, 'a> ExportableItemsChecker<'tcx, 'a> {
|
||||
fn check(&mut self) {
|
||||
match self.tcx.def_kind(self.item_id) {
|
||||
DefKind::Fn | DefKind::AssocFn => self.check_fn(),
|
||||
DefKind::Enum | DefKind::Struct | DefKind::Union => self.check_ty(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn(&mut self) {
|
||||
let def_id = self.item_id.expect_local();
|
||||
let span = self.tcx.def_span(def_id);
|
||||
|
||||
if self.tcx.generics_of(def_id).requires_monomorphization(self.tcx) {
|
||||
self.tcx.dcx().emit_err(UnexportableItem::GenericFn(span));
|
||||
return;
|
||||
}
|
||||
|
||||
let sig = self.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
|
||||
if !matches!(sig.abi, ExternAbi::C { .. }) {
|
||||
self.tcx.dcx().emit_err(UnexportableItem::FnAbi(span));
|
||||
return;
|
||||
}
|
||||
|
||||
let sig = self
|
||||
.tcx
|
||||
.try_normalize_erasing_regions(ty::TypingEnv::non_body_analysis(self.tcx, def_id), sig)
|
||||
.unwrap_or(sig);
|
||||
|
||||
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
|
||||
let decl = self.tcx.hir_fn_decl_by_hir_id(hir_id).unwrap();
|
||||
|
||||
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
|
||||
self.check_nested_types_are_exportable(*input_ty, input_hir.span);
|
||||
}
|
||||
|
||||
if let hir::FnRetTy::Return(ret_hir) = decl.output {
|
||||
self.check_nested_types_are_exportable(sig.output(), ret_hir.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ty(&mut self) {
|
||||
let ty = self.tcx.type_of(self.item_id).skip_binder();
|
||||
if let ty::Adt(adt_def, _) = ty.kind() {
|
||||
if !adt_def.repr().inhibit_struct_field_reordering() {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_err(UnexportableItem::TypeRepr(self.tcx.def_span(self.item_id)));
|
||||
}
|
||||
|
||||
// FIXME: support `#[export(unsafe_stable_abi = "hash")]` syntax
|
||||
for variant in adt_def.variants() {
|
||||
for field in &variant.fields {
|
||||
if !field.vis.is_public() {
|
||||
self.tcx.dcx().emit_err(UnexportableItem::AdtWithPrivFields {
|
||||
span: self.tcx.def_span(self.item_id),
|
||||
vis_note: self.tcx.def_span(field.did),
|
||||
field_name: field.name.as_str(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_nested_types_are_exportable(&mut self, ty: Ty<'tcx>, ty_span: Span) {
|
||||
let res = ty.visit_with(self);
|
||||
if let Some(err_cause) = res.break_value() {
|
||||
self.tcx.dcx().emit_err(UnexportableItem::TypeInInterface {
|
||||
span: self.tcx.def_span(self.item_id),
|
||||
desc: self.tcx.def_descr(self.item_id),
|
||||
ty: &format!("{}", err_cause),
|
||||
ty_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, 'a> TypeVisitor<TyCtxt<'tcx>> for ExportableItemsChecker<'tcx, 'a> {
|
||||
type Result = ControlFlow<Ty<'tcx>>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
match ty.kind() {
|
||||
ty::Adt(adt_def, _) => {
|
||||
let did = adt_def.did();
|
||||
let exportable = if did.is_local() {
|
||||
self.exportable_items.contains(&did)
|
||||
} else {
|
||||
self.tcx.is_exportable(did)
|
||||
};
|
||||
if !exportable {
|
||||
return ControlFlow::Break(ty);
|
||||
}
|
||||
for variant in adt_def.variants() {
|
||||
for field in &variant.fields {
|
||||
let field_ty = self.tcx.type_of(field.did).instantiate_identity();
|
||||
field_ty.visit_with(self)?;
|
||||
}
|
||||
}
|
||||
|
||||
return ty.super_visit_with(self);
|
||||
}
|
||||
|
||||
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool | ty::Char | ty::Error(_) => {}
|
||||
|
||||
ty::Array(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::Param(_)
|
||||
| ty::Closure(_, _)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Tuple(_)
|
||||
| ty::Pat(..)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::CoroutineWitness(_, _)
|
||||
| ty::Never
|
||||
| ty::UnsafeBinder(_)
|
||||
| ty::Alias(ty::AliasTyKind::Opaque, _) => {
|
||||
return ControlFlow::Break(ty);
|
||||
}
|
||||
|
||||
ty::Alias(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => unreachable!(),
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Exportable items:
|
||||
///
|
||||
/// 1. Structs/enums/unions with a stable representation (e.g. repr(i32) or repr(C)).
|
||||
/// 2. Primitive types.
|
||||
/// 3. Non-generic functions with a stable ABI (e.g. extern "C") for which every user
|
||||
/// defined type used in the signature is also marked as `#[export]`.
|
||||
fn exportable_items_provider_local<'tcx>(tcx: TyCtxt<'tcx>, _: LocalCrate) -> &'tcx [DefId] {
|
||||
if !tcx.crate_types().contains(&CrateType::Sdylib) && !tcx.is_sdylib_interface_build() {
|
||||
return &[];
|
||||
}
|
||||
|
||||
let mut visitor = ExportableItemCollector::new(tcx);
|
||||
tcx.hir_walk_toplevel_module(&mut visitor);
|
||||
let exportable_items = visitor.exportable_items;
|
||||
for item_id in exportable_items.iter() {
|
||||
let mut validator =
|
||||
ExportableItemsChecker { tcx, exportable_items: &exportable_items, item_id: *item_id };
|
||||
validator.check();
|
||||
}
|
||||
|
||||
tcx.arena.alloc_from_iter(exportable_items.into_iter())
|
||||
}
|
||||
|
||||
struct ImplsOrderVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
order: FxIndexMap<DefId, usize>,
|
||||
}
|
||||
|
||||
impl<'tcx> ImplsOrderVisitor<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> ImplsOrderVisitor<'tcx> {
|
||||
ImplsOrderVisitor { tcx, order: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ImplsOrderVisitor<'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
if let hir::ItemKind::Impl(impl_) = item.kind
|
||||
&& impl_.of_trait.is_none()
|
||||
&& self.tcx.is_exportable(item.owner_id.def_id.to_def_id())
|
||||
{
|
||||
self.order.insert(item.owner_id.def_id.to_def_id(), self.order.len());
|
||||
}
|
||||
intravisit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
/// During symbol mangling rustc uses a special index to distinguish between two impls of
|
||||
/// the same type in the same module(See `DisambiguatedDefPathData`). For exportable items
|
||||
/// we cannot use the current approach because it is dependent on the compiler's
|
||||
/// implementation.
|
||||
///
|
||||
/// In order to make disambiguation independent of the compiler version we can assign an
|
||||
/// id to each impl according to the relative order of elements in the source code.
|
||||
fn stable_order_of_exportable_impls<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
_: LocalCrate,
|
||||
) -> &'tcx FxIndexMap<DefId, usize> {
|
||||
if !tcx.crate_types().contains(&CrateType::Sdylib) && !tcx.is_sdylib_interface_build() {
|
||||
return tcx.arena.alloc(FxIndexMap::<DefId, usize>::default());
|
||||
}
|
||||
|
||||
let mut vis = ImplsOrderVisitor::new(tcx);
|
||||
tcx.hir_walk_toplevel_module(&mut vis);
|
||||
tcx.arena.alloc(vis.order)
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
exportable_items: exportable_items_provider_local,
|
||||
stable_order_of_exportable_impls,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
|
@ -1422,6 +1422,13 @@ pub(crate) struct IncorrectTarget<'a> {
|
|||
pub at_least: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_incorrect_crate_type)]
|
||||
pub(crate) struct IncorrectCrateType {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_useless_assignment)]
|
||||
pub(crate) struct UselessAssignment<'a> {
|
||||
|
|
@ -1919,3 +1926,50 @@ pub(crate) struct UnsupportedAttributesInWhere {
|
|||
#[primary_span]
|
||||
pub span: MultiSpan,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum UnexportableItem<'a> {
|
||||
#[diag(passes_unexportable_item)]
|
||||
Item {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
descr: &'a str,
|
||||
},
|
||||
|
||||
#[diag(passes_unexportable_generic_fn)]
|
||||
GenericFn(#[primary_span] Span),
|
||||
|
||||
#[diag(passes_unexportable_fn_abi)]
|
||||
FnAbi(#[primary_span] Span),
|
||||
|
||||
#[diag(passes_unexportable_type_repr)]
|
||||
TypeRepr(#[primary_span] Span),
|
||||
|
||||
#[diag(passes_unexportable_type_in_interface)]
|
||||
TypeInInterface {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
desc: &'a str,
|
||||
ty: &'a str,
|
||||
#[label]
|
||||
ty_span: Span,
|
||||
},
|
||||
|
||||
#[diag(passes_unexportable_priv_item)]
|
||||
PrivItem {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note]
|
||||
vis_note: Span,
|
||||
vis_descr: &'a str,
|
||||
},
|
||||
|
||||
#[diag(passes_unexportable_adt_with_private_fields)]
|
||||
AdtWithPrivFields {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note]
|
||||
vis_note: Span,
|
||||
field_name: &'a str,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ use rustc_session::cstore::ExternCrate;
|
|||
use rustc_span::Span;
|
||||
|
||||
use crate::errors::{
|
||||
DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
|
||||
DuplicateLangItem, IncorrectCrateType, IncorrectTarget, LangItemOnIncorrectTarget,
|
||||
UnknownLangItem,
|
||||
};
|
||||
use crate::weak_lang_items;
|
||||
|
||||
|
|
@ -236,6 +237,10 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if self.tcx.crate_types().contains(&rustc_session::config::CrateType::Sdylib) {
|
||||
self.tcx.dcx().emit_err(IncorrectCrateType { span: attr_span });
|
||||
}
|
||||
|
||||
self.collect_item(lang_item, item_def_id.to_def_id(), Some(item_span));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use rustc_middle::query::Providers;
|
|||
|
||||
pub mod abi_test;
|
||||
mod check_attr;
|
||||
mod check_export;
|
||||
pub mod dead;
|
||||
mod debugger_visualizer;
|
||||
mod diagnostic_items;
|
||||
|
|
@ -54,4 +55,5 @@ pub fn provide(providers: &mut Providers) {
|
|||
reachable::provide(providers);
|
||||
stability::provide(providers);
|
||||
upvars::provide(providers);
|
||||
check_export::provide(providers);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -435,10 +435,12 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
|||
fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
|
||||
let effective_visibilities = &tcx.effective_visibilities(());
|
||||
|
||||
let any_library = tcx
|
||||
.crate_types()
|
||||
.iter()
|
||||
.any(|ty| *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro);
|
||||
let any_library = tcx.crate_types().iter().any(|ty| {
|
||||
*ty == CrateType::Rlib
|
||||
|| *ty == CrateType::Dylib
|
||||
|| *ty == CrateType::ProcMacro
|
||||
|| *ty == CrateType::Sdylib
|
||||
});
|
||||
let mut reachable_context = ReachableContext {
|
||||
tcx,
|
||||
maybe_typeck_results: None,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
|
|||
| CrateType::ProcMacro
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Executable
|
||||
| CrateType::Staticlib => true,
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Sdylib => true,
|
||||
CrateType::Rlib => false,
|
||||
});
|
||||
if !needs_check {
|
||||
|
|
|
|||
|
|
@ -1169,6 +1169,10 @@ impl OutputFilenames {
|
|||
.unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
|
||||
}
|
||||
|
||||
pub fn interface_path(&self) -> PathBuf {
|
||||
self.out_directory.join(format!("lib{}.rs", self.crate_stem))
|
||||
}
|
||||
|
||||
/// Gets the output path where a compilation artifact of the given type
|
||||
/// should be placed on disk.
|
||||
fn output_path(&self, flavor: OutputType) -> PathBuf {
|
||||
|
|
@ -1452,13 +1456,17 @@ pub enum CrateType {
|
|||
Staticlib,
|
||||
Cdylib,
|
||||
ProcMacro,
|
||||
Sdylib,
|
||||
}
|
||||
|
||||
impl CrateType {
|
||||
pub fn has_metadata(self) -> bool {
|
||||
match self {
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
||||
CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib => false,
|
||||
CrateType::Executable
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Sdylib => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2818,6 +2826,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
|
|||
"cdylib" => CrateType::Cdylib,
|
||||
"bin" => CrateType::Executable,
|
||||
"proc-macro" => CrateType::ProcMacro,
|
||||
"sdylib" => CrateType::Sdylib,
|
||||
_ => {
|
||||
return Err(format!(
|
||||
"unknown crate type: `{part}`, expected one of: \
|
||||
|
|
@ -2915,6 +2924,7 @@ impl fmt::Display for CrateType {
|
|||
CrateType::Staticlib => "staticlib".fmt(f),
|
||||
CrateType::Cdylib => "cdylib".fmt(f),
|
||||
CrateType::ProcMacro => "proc-macro".fmt(f),
|
||||
CrateType::Sdylib => "sdylib".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub struct CrateSource {
|
|||
pub dylib: Option<(PathBuf, PathKind)>,
|
||||
pub rlib: Option<(PathBuf, PathKind)>,
|
||||
pub rmeta: Option<(PathBuf, PathKind)>,
|
||||
pub sdylib_interface: Option<(PathBuf, PathKind)>,
|
||||
}
|
||||
|
||||
impl CrateSource {
|
||||
|
|
|
|||
|
|
@ -2113,6 +2113,8 @@ options! {
|
|||
"emit noalias metadata for box (default: yes)"),
|
||||
branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
|
||||
"set options for branch target identification and pointer authentication on AArch64"),
|
||||
build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED],
|
||||
"whether the stable interface is being built"),
|
||||
cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
|
||||
"instrument control-flow architecture protection"),
|
||||
check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ pub fn filename_for_input(
|
|||
CrateType::Rlib => {
|
||||
OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rlib")))
|
||||
}
|
||||
CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
|
||||
CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib | CrateType::Sdylib => {
|
||||
let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
|
||||
OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
|
||||
}
|
||||
|
|
@ -167,6 +167,7 @@ pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[
|
|||
(sym::staticlib, CrateType::Staticlib),
|
||||
(sym::proc_dash_macro, CrateType::ProcMacro),
|
||||
(sym::bin, CrateType::Executable),
|
||||
(sym::sdylib, CrateType::Sdylib),
|
||||
];
|
||||
|
||||
pub fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
|
||||
|
|
@ -187,6 +188,11 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
|
|||
return vec![CrateType::Executable];
|
||||
}
|
||||
|
||||
// Shadow `sdylib` crate type in interface build.
|
||||
if session.opts.unstable_opts.build_sdylib_interface {
|
||||
return vec![CrateType::Rlib];
|
||||
}
|
||||
|
||||
// Only check command line flags if present. If no types are specified by
|
||||
// command line, then reuse the empty `base` Vec to hold the types that
|
||||
// will be found in crate attributes.
|
||||
|
|
|
|||
|
|
@ -914,6 +914,7 @@ symbols! {
|
|||
explicit_generic_args_with_impl_trait,
|
||||
explicit_tail_calls,
|
||||
export_name,
|
||||
export_stable,
|
||||
expr,
|
||||
expr_2021,
|
||||
expr_fragment_specifier_2024,
|
||||
|
|
@ -1878,6 +1879,7 @@ symbols! {
|
|||
saturating_add,
|
||||
saturating_div,
|
||||
saturating_sub,
|
||||
sdylib,
|
||||
search_unbox,
|
||||
select_unpredictable,
|
||||
self_in_typedefs,
|
||||
|
|
|
|||
181
compiler/rustc_symbol_mangling/src/export.rs
Normal file
181
compiler/rustc_symbol_mangling/src/export.rs
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
use std::assert_matches::debug_assert_matches;
|
||||
|
||||
use rustc_abi::IntegerType;
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_hashes::Hash128;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
|
||||
trait AbiHashStable<'tcx> {
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher);
|
||||
}
|
||||
macro_rules! default_hash_impl {
|
||||
($($t:ty,)+) => {
|
||||
$(impl<'tcx> AbiHashStable<'tcx> for $t {
|
||||
#[inline]
|
||||
fn abi_hash(&self, _tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
::std::hash::Hash::hash(self, hasher);
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
default_hash_impl! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, }
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for bool {
|
||||
#[inline]
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
(if *self { 1u8 } else { 0u8 }).abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for str {
|
||||
#[inline]
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
self.as_bytes().abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for String {
|
||||
#[inline]
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
self[..].abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for Symbol {
|
||||
#[inline]
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
self.as_str().abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: AbiHashStable<'tcx>> AbiHashStable<'tcx> for [T] {
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
self.len().abi_hash(tcx, hasher);
|
||||
for item in self {
|
||||
item.abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> {
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
match self.kind() {
|
||||
ty::Bool => sym::bool.abi_hash(tcx, hasher),
|
||||
ty::Char => sym::char.abi_hash(tcx, hasher),
|
||||
ty::Int(int_ty) => int_ty.name_str().abi_hash(tcx, hasher),
|
||||
ty::Uint(uint_ty) => uint_ty.name_str().abi_hash(tcx, hasher),
|
||||
ty::Float(float_ty) => float_ty.name_str().abi_hash(tcx, hasher),
|
||||
|
||||
ty::Adt(adt_def, args) => {
|
||||
adt_def.is_struct().abi_hash(tcx, hasher);
|
||||
adt_def.is_enum().abi_hash(tcx, hasher);
|
||||
adt_def.is_union().abi_hash(tcx, hasher);
|
||||
|
||||
if let Some(align) = adt_def.repr().align {
|
||||
align.bits().abi_hash(tcx, hasher);
|
||||
}
|
||||
|
||||
if let Some(integer) = adt_def.repr().int {
|
||||
match integer {
|
||||
IntegerType::Pointer(sign) => sign.abi_hash(tcx, hasher),
|
||||
IntegerType::Fixed(integer, sign) => {
|
||||
integer.int_ty_str().abi_hash(tcx, hasher);
|
||||
sign.abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(pack) = adt_def.repr().pack {
|
||||
pack.bits().abi_hash(tcx, hasher);
|
||||
}
|
||||
|
||||
adt_def.repr().c().abi_hash(tcx, hasher);
|
||||
|
||||
for variant in adt_def.variants() {
|
||||
variant.name.abi_hash(tcx, hasher);
|
||||
for field in &variant.fields {
|
||||
field.name.abi_hash(tcx, hasher);
|
||||
let field_ty = tcx.type_of(field.did).instantiate_identity();
|
||||
field_ty.abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
args.abi_hash(tcx, hasher);
|
||||
}
|
||||
|
||||
ty::Tuple(args) if args.len() == 0 => {}
|
||||
|
||||
// FIXME: Not yet supported.
|
||||
ty::Foreign(_)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_, _)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(_, _)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_)
|
||||
| ty::UnsafeBinder(_) => unreachable!(),
|
||||
|
||||
ty::Error(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for ty::FnSig<'tcx> {
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
for ty in self.inputs_and_output {
|
||||
ty.abi_hash(tcx, hasher);
|
||||
}
|
||||
self.safety.is_safe().abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for ty::GenericArg<'tcx> {
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
self.unpack().abi_hash(tcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AbiHashStable<'tcx> for ty::GenericArgKind<'tcx> {
|
||||
fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
|
||||
match self {
|
||||
ty::GenericArgKind::Type(t) => t.abi_hash(tcx, hasher),
|
||||
ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_hash_of_export_fn<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
) -> String {
|
||||
let def_id = instance.def_id();
|
||||
debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
|
||||
|
||||
let args = instance.args;
|
||||
let sig_ty = tcx.fn_sig(def_id).instantiate(tcx, args);
|
||||
let sig_ty = tcx.instantiate_bound_regions_with_erased(sig_ty);
|
||||
|
||||
let hash = {
|
||||
let mut hasher = StableHasher::new();
|
||||
sig_ty.abi_hash(tcx, &mut hasher);
|
||||
hasher.finish::<Hash128>()
|
||||
};
|
||||
|
||||
hash.as_u128().to_string()
|
||||
}
|
||||
|
|
@ -92,6 +92,7 @@
|
|||
#![cfg_attr(bootstrap, feature(let_chains))]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
@ -104,6 +105,7 @@ use rustc_middle::ty::{self, Instance, TyCtxt};
|
|||
use rustc_session::config::SymbolManglingVersion;
|
||||
use tracing::debug;
|
||||
|
||||
mod export;
|
||||
mod hashed;
|
||||
mod legacy;
|
||||
mod v0;
|
||||
|
|
@ -296,12 +298,21 @@ fn compute_symbol_name<'tcx>(
|
|||
tcx.symbol_mangling_version(mangling_version_crate)
|
||||
};
|
||||
|
||||
let symbol = match mangling_version {
|
||||
SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
|
||||
SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
|
||||
SymbolManglingVersion::Hashed => hashed::mangle(tcx, instance, instantiating_crate, || {
|
||||
v0::mangle(tcx, instance, instantiating_crate)
|
||||
}),
|
||||
let symbol = match tcx.is_exportable(def_id) {
|
||||
true => format!(
|
||||
"{}.{}",
|
||||
v0::mangle(tcx, instance, instantiating_crate, true),
|
||||
export::compute_hash_of_export_fn(tcx, instance)
|
||||
),
|
||||
false => match mangling_version {
|
||||
SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
|
||||
SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate, false),
|
||||
SymbolManglingVersion::Hashed => {
|
||||
hashed::mangle(tcx, instance, instantiating_crate, || {
|
||||
v0::mangle(tcx, instance, instantiating_crate, false)
|
||||
})
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ pub(super) fn mangle<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
instantiating_crate: Option<CrateNum>,
|
||||
is_exportable: bool,
|
||||
) -> String {
|
||||
let def_id = instance.def_id();
|
||||
// FIXME(eddyb) this should ideally not be needed.
|
||||
|
|
@ -35,6 +36,7 @@ pub(super) fn mangle<'tcx>(
|
|||
let mut cx: SymbolMangler<'_> = SymbolMangler {
|
||||
tcx,
|
||||
start_offset: prefix.len(),
|
||||
is_exportable,
|
||||
paths: FxHashMap::default(),
|
||||
types: FxHashMap::default(),
|
||||
consts: FxHashMap::default(),
|
||||
|
|
@ -93,6 +95,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin
|
|||
let mut cx: SymbolMangler<'_> = SymbolMangler {
|
||||
tcx,
|
||||
start_offset: prefix.len(),
|
||||
is_exportable: false,
|
||||
paths: FxHashMap::default(),
|
||||
types: FxHashMap::default(),
|
||||
consts: FxHashMap::default(),
|
||||
|
|
@ -135,6 +138,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
|
|||
let mut cx = SymbolMangler {
|
||||
tcx,
|
||||
start_offset: 0,
|
||||
is_exportable: false,
|
||||
paths: FxHashMap::default(),
|
||||
types: FxHashMap::default(),
|
||||
consts: FxHashMap::default(),
|
||||
|
|
@ -163,6 +167,7 @@ struct SymbolMangler<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
binders: Vec<BinderLevel>,
|
||||
out: String,
|
||||
is_exportable: bool,
|
||||
|
||||
/// The length of the prefix in `out` (e.g. 2 for `_R`).
|
||||
start_offset: usize,
|
||||
|
|
@ -376,7 +381,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
args,
|
||||
)?;
|
||||
} else {
|
||||
self.push_disambiguator(key.disambiguated_data.disambiguator as u64);
|
||||
let exported_impl_order = self.tcx.stable_order_of_exportable_impls(impl_def_id.krate);
|
||||
let disambiguator = match self.is_exportable {
|
||||
true => exported_impl_order[&impl_def_id] as u64,
|
||||
false => {
|
||||
exported_impl_order.len() as u64 + key.disambiguated_data.disambiguator as u64
|
||||
}
|
||||
};
|
||||
self.push_disambiguator(disambiguator);
|
||||
self.print_def_path(parent_def_id, &[])?;
|
||||
}
|
||||
|
||||
|
|
@ -818,8 +830,10 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
|
||||
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
|
||||
self.push("C");
|
||||
let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
|
||||
self.push_disambiguator(stable_crate_id.as_u64());
|
||||
if !self.is_exportable {
|
||||
let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
|
||||
self.push_disambiguator(stable_crate_id.as_u64());
|
||||
}
|
||||
let name = self.tcx.crate_name(cnum);
|
||||
self.push_ident(name.as_str());
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ ignore = [
|
|||
"/tests/debuginfo/", # These tests are somewhat sensitive to source code layout.
|
||||
"/tests/incremental/", # These tests are somewhat sensitive to source code layout.
|
||||
"/tests/pretty/", # These tests are very sensitive to source code layout.
|
||||
"/tests/run-make/export", # These tests contain syntax errors.
|
||||
"/tests/run-make/translation/test.rs", # This test contains syntax errors.
|
||||
"/tests/rustdoc/", # Some have syntax errors, some are whitespace-sensitive.
|
||||
"/tests/rustdoc-gui/", # Some tests are sensitive to source code layout.
|
||||
|
|
|
|||
3
tests/run-make/export/compile-interface-error/app.rs
Normal file
3
tests/run-make/export/compile-interface-error/app.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
extern crate libr;
|
||||
|
||||
fn main() {}
|
||||
5
tests/run-make/export/compile-interface-error/liblibr.rs
Normal file
5
tests/run-make/export/compile-interface-error/liblibr.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#![feature(export_stable)]
|
||||
|
||||
// interface file is broken(priv fn):
|
||||
#[export_stable]
|
||||
extern "C" fn foo();
|
||||
9
tests/run-make/export/compile-interface-error/rmake.rs
Normal file
9
tests/run-make/export/compile-interface-error/rmake.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
use run_make_support::rustc;
|
||||
|
||||
fn main() {
|
||||
// Do not produce the interface, use the broken one.
|
||||
rustc()
|
||||
.input("app.rs")
|
||||
.run_fail()
|
||||
.assert_stderr_contains("couldn't compile interface");
|
||||
}
|
||||
7
tests/run-make/export/disambiguator/app.rs
Normal file
7
tests/run-make/export/disambiguator/app.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extern crate libr;
|
||||
|
||||
use libr::*;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(S::<S2>::foo(), 2);
|
||||
}
|
||||
27
tests/run-make/export/disambiguator/libr.rs
Normal file
27
tests/run-make/export/disambiguator/libr.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// `S::<S2>::foo` and `S::<S1>::foo` have same `DefPath` modulo disambiguator.
|
||||
// `libr.rs` interface may not contain `S::<S1>::foo` as private items aren't
|
||||
// exportable. We should make sure that original `S::<S2>::foo` and the one
|
||||
// produced during interface generation have same mangled names.
|
||||
|
||||
#![feature(export_stable)]
|
||||
#![crate_type = "sdylib"]
|
||||
|
||||
#[export_stable]
|
||||
#[repr(C)]
|
||||
pub struct S<T>(pub T);
|
||||
|
||||
struct S1;
|
||||
pub struct S2;
|
||||
|
||||
impl S<S1> {
|
||||
extern "C" fn foo() -> i32 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
#[export_stable]
|
||||
impl S<S2> {
|
||||
pub extern "C" fn foo() -> i32 {
|
||||
2
|
||||
}
|
||||
}
|
||||
12
tests/run-make/export/disambiguator/rmake.rs
Normal file
12
tests/run-make/export/disambiguator/rmake.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use run_make_support::rustc;
|
||||
|
||||
fn main() {
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "1")
|
||||
.input("libr.rs")
|
||||
.run();
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
||||
.input("app.rs")
|
||||
.run();
|
||||
}
|
||||
6
tests/run-make/export/extern-opt/app.rs
Normal file
6
tests/run-make/export/extern-opt/app.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
extern crate libr;
|
||||
use libr::*;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(foo(1), 1);
|
||||
}
|
||||
4
tests/run-make/export/extern-opt/libinterface.rs
Normal file
4
tests/run-make/export/extern-opt/libinterface.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#![feature(export_stable)]
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo(x: i32) -> i32;
|
||||
5
tests/run-make/export/extern-opt/libr.rs
Normal file
5
tests/run-make/export/extern-opt/libr.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#![feature(export_stable)]
|
||||
#![crate_type = "sdylib"]
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo(x: i32) -> i32 { x }
|
||||
23
tests/run-make/export/extern-opt/rmake.rs
Normal file
23
tests/run-make/export/extern-opt/rmake.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use run_make_support::{rustc, dynamic_lib_name};
|
||||
|
||||
fn main() {
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "1")
|
||||
.input("libr.rs")
|
||||
.run();
|
||||
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
||||
.input("app.rs")
|
||||
.extern_("libr", "libinterface.rs")
|
||||
.extern_("libr", dynamic_lib_name("libr"))
|
||||
.run();
|
||||
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
||||
.input("app.rs")
|
||||
.extern_("libr", "interface.rs") // wrong interface format
|
||||
.extern_("libr", dynamic_lib_name("libr"))
|
||||
.run_fail()
|
||||
.assert_stderr_contains("extern location for libr does not exist");
|
||||
}
|
||||
8
tests/run-make/export/simple/app.rs
Normal file
8
tests/run-make/export/simple/app.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extern crate libr;
|
||||
use libr::*;
|
||||
|
||||
fn main() {
|
||||
let s = m::S { x: 42 };
|
||||
assert_eq!(m::foo1(s), 42);
|
||||
assert_eq!(m::S::foo2(1), 1);
|
||||
}
|
||||
22
tests/run-make/export/simple/libr.rs
Normal file
22
tests/run-make/export/simple/libr.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#![feature(export_stable)]
|
||||
#![crate_type = "sdylib"]
|
||||
|
||||
#[export_stable]
|
||||
pub mod m {
|
||||
#[repr(C)]
|
||||
pub struct S {
|
||||
pub x: i32,
|
||||
}
|
||||
|
||||
pub extern "C" fn foo1(x: S) -> i32 {
|
||||
x.x
|
||||
}
|
||||
|
||||
pub type Integer = i32;
|
||||
|
||||
impl S {
|
||||
pub extern "C" fn foo2(x: Integer) -> Integer {
|
||||
x
|
||||
}
|
||||
}
|
||||
}
|
||||
12
tests/run-make/export/simple/rmake.rs
Normal file
12
tests/run-make/export/simple/rmake.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use run_make_support::rustc;
|
||||
|
||||
fn main() {
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "1")
|
||||
.input("libr.rs")
|
||||
.run();
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "2")
|
||||
.input("app.rs")
|
||||
.run();
|
||||
}
|
||||
2
tests/ui/attributes/export/crate-type-2.rs
Normal file
2
tests/ui/attributes/export/crate-type-2.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
//@ compile-flags: --crate-type=sdylib
|
||||
//~^ ERROR `sdylib` crate type is unstable
|
||||
9
tests/ui/attributes/export/crate-type-2.stderr
Normal file
9
tests/ui/attributes/export/crate-type-2.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0658]: `sdylib` crate type is unstable
|
||||
|
|
||||
= note: see issue #139939 <https://github.com/rust-lang/rust/issues/139939> for more information
|
||||
= help: add `#![feature(export_stable)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
2
tests/ui/attributes/export/crate-type.rs
Normal file
2
tests/ui/attributes/export/crate-type.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#![crate_type = "sdylib"]
|
||||
//~^ ERROR `sdylib` crate type is unstable
|
||||
9
tests/ui/attributes/export/crate-type.stderr
Normal file
9
tests/ui/attributes/export/crate-type.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0658]: `sdylib` crate type is unstable
|
||||
|
|
||||
= note: see issue #139939 <https://github.com/rust-lang/rust/issues/139939> for more information
|
||||
= help: add `#![feature(export_stable)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
139
tests/ui/attributes/export/exportable.rs
Normal file
139
tests/ui/attributes/export/exportable.rs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
//@ compile-flags: -Zunstable-options -Csymbol-mangling-version=v0
|
||||
|
||||
#![crate_type = "sdylib"]
|
||||
#![allow(incomplete_features, improper_ctypes_definitions)]
|
||||
#![feature(export_stable)]
|
||||
#![feature(inherent_associated_types)]
|
||||
|
||||
mod m {
|
||||
#[export_stable]
|
||||
pub struct S;
|
||||
//~^ ERROR private items are not exportable
|
||||
|
||||
pub fn foo() -> i32 { 0 }
|
||||
//~^ ERROR only functions with "C" ABI are exportable
|
||||
}
|
||||
|
||||
#[export_stable]
|
||||
pub use m::foo;
|
||||
|
||||
#[export_stable]
|
||||
pub mod m1 {
|
||||
#[repr(C)]
|
||||
pub struct S1; // OK, public type with stable repr
|
||||
|
||||
struct S2;
|
||||
|
||||
pub struct S3;
|
||||
//~^ ERROR types with unstable layout are not exportable
|
||||
}
|
||||
|
||||
pub mod fn_sig {
|
||||
#[export_stable]
|
||||
pub fn foo1() {}
|
||||
//~^ ERROR only functions with "C" ABI are exportable
|
||||
|
||||
#[export_stable]
|
||||
#[repr(C)]
|
||||
pub struct S;
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo2(x: S) -> i32 { 0 }
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo3(x: Box<S>) -> i32 { 0 }
|
||||
//~^ ERROR function with `#[export_stable]` attribute uses type `Box<fn_sig::S>`, which is not exportable
|
||||
}
|
||||
|
||||
pub mod impl_item {
|
||||
pub struct S;
|
||||
|
||||
impl S {
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo1(&self) -> i32 { 0 }
|
||||
//~^ ERROR method with `#[export_stable]` attribute uses type `&impl_item::S`, which is not exportable
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo2(self) -> i32 { 0 }
|
||||
//~^ ERROR method with `#[export_stable]` attribute uses type `impl_item::S`, which is not exportable
|
||||
}
|
||||
|
||||
pub struct S2<T>(T);
|
||||
|
||||
impl<T> S2<T> {
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo1(&self) {}
|
||||
//~^ ERROR generic functions are not exportable
|
||||
}
|
||||
}
|
||||
|
||||
pub mod tys {
|
||||
pub trait Trait {
|
||||
type Type;
|
||||
}
|
||||
pub struct S;
|
||||
|
||||
impl Trait for S {
|
||||
type Type = (u32,);
|
||||
}
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo1(x: <S as Trait>::Type) -> u32 { x.0 }
|
||||
//~^ ERROR function with `#[export_stable]` attribute uses type `(u32,)`, which is not exportable
|
||||
|
||||
#[export_stable]
|
||||
pub type Type = [i32; 4];
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo2(_x: Type) {}
|
||||
//~^ ERROR function with `#[export_stable]` attribute uses type `[i32; 4]`, which is not exportable
|
||||
|
||||
impl S {
|
||||
#[export_stable]
|
||||
pub type Type = extern "C" fn();
|
||||
}
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo3(_x: S::Type) {}
|
||||
//~^ ERROR function with `#[export_stable]` attribute uses type `extern "C" fn()`, which is not exportable
|
||||
|
||||
#[export_stable]
|
||||
pub extern "C" fn foo4() -> impl Copy {
|
||||
//~^ ERROR function with `#[export_stable]` attribute uses type `impl Copy`, which is not exportable
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privacy {
|
||||
#[export_stable]
|
||||
#[repr(C)]
|
||||
pub struct S1 {
|
||||
pub x: i32
|
||||
}
|
||||
|
||||
#[export_stable]
|
||||
#[repr(C)]
|
||||
pub struct S2 {
|
||||
//~^ ERROR ADT types with private fields are not exportable
|
||||
x: i32
|
||||
}
|
||||
|
||||
#[export_stable]
|
||||
#[repr(i32)]
|
||||
enum E {
|
||||
//~^ ERROR private items are not exportable
|
||||
Variant1 { x: i32 }
|
||||
}
|
||||
}
|
||||
|
||||
pub mod use_site {
|
||||
#[export_stable]
|
||||
pub trait Trait {}
|
||||
//~^ ERROR trait's are not exportable
|
||||
|
||||
#[export_stable]
|
||||
pub const C: i32 = 0;
|
||||
//~^ ERROR constant's are not exportable
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
130
tests/ui/attributes/export/exportable.stderr
Normal file
130
tests/ui/attributes/export/exportable.stderr
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
error: private items are not exportable
|
||||
--> $DIR/exportable.rs:10:5
|
||||
|
|
||||
LL | pub struct S;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: is only usable at visibility `pub(crate)`
|
||||
--> $DIR/exportable.rs:10:5
|
||||
|
|
||||
LL | pub struct S;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: private items are not exportable
|
||||
--> $DIR/exportable.rs:123:5
|
||||
|
|
||||
LL | enum E {
|
||||
| ^^^^^^
|
||||
|
|
||||
note: is only usable at visibility `pub(self)`
|
||||
--> $DIR/exportable.rs:123:5
|
||||
|
|
||||
LL | enum E {
|
||||
| ^^^^^^
|
||||
|
||||
error: trait's are not exportable
|
||||
--> $DIR/exportable.rs:131:5
|
||||
|
|
||||
LL | pub trait Trait {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: constant's are not exportable
|
||||
--> $DIR/exportable.rs:135:5
|
||||
|
|
||||
LL | pub const C: i32 = 0;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: only functions with "C" ABI are exportable
|
||||
--> $DIR/exportable.rs:13:5
|
||||
|
|
||||
LL | pub fn foo() -> i32 { 0 }
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: types with unstable layout are not exportable
|
||||
--> $DIR/exportable.rs:27:5
|
||||
|
|
||||
LL | pub struct S3;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: only functions with "C" ABI are exportable
|
||||
--> $DIR/exportable.rs:33:5
|
||||
|
|
||||
LL | pub fn foo1() {}
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: function with `#[export_stable]` attribute uses type `Box<fn_sig::S>`, which is not exportable
|
||||
--> $DIR/exportable.rs:44:5
|
||||
|
|
||||
LL | pub extern "C" fn foo3(x: Box<S>) -> i32 { 0 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^^
|
||||
| |
|
||||
| not exportable
|
||||
|
||||
error: method with `#[export_stable]` attribute uses type `&impl_item::S`, which is not exportable
|
||||
--> $DIR/exportable.rs:53:9
|
||||
|
|
||||
LL | pub extern "C" fn foo1(&self) -> i32 { 0 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^-----^^^^^^^^
|
||||
| |
|
||||
| not exportable
|
||||
|
||||
error: method with `#[export_stable]` attribute uses type `impl_item::S`, which is not exportable
|
||||
--> $DIR/exportable.rs:57:9
|
||||
|
|
||||
LL | pub extern "C" fn foo2(self) -> i32 { 0 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^----^^^^^^^^
|
||||
| |
|
||||
| not exportable
|
||||
|
||||
error: generic functions are not exportable
|
||||
--> $DIR/exportable.rs:65:9
|
||||
|
|
||||
LL | pub extern "C" fn foo1(&self) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: function with `#[export_stable]` attribute uses type `(u32,)`, which is not exportable
|
||||
--> $DIR/exportable.rs:81:5
|
||||
|
|
||||
LL | pub extern "C" fn foo1(x: <S as Trait>::Type) -> u32 { x.0 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^------------------^^^^^^^^
|
||||
| |
|
||||
| not exportable
|
||||
|
||||
error: function with `#[export_stable]` attribute uses type `[i32; 4]`, which is not exportable
|
||||
--> $DIR/exportable.rs:88:5
|
||||
|
|
||||
LL | pub extern "C" fn foo2(_x: Type) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^----^
|
||||
| |
|
||||
| not exportable
|
||||
|
||||
error: function with `#[export_stable]` attribute uses type `extern "C" fn()`, which is not exportable
|
||||
--> $DIR/exportable.rs:97:5
|
||||
|
|
||||
LL | pub extern "C" fn foo3(_x: S::Type) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^
|
||||
| |
|
||||
| not exportable
|
||||
|
||||
error: function with `#[export_stable]` attribute uses type `impl Copy`, which is not exportable
|
||||
--> $DIR/exportable.rs:101:5
|
||||
|
|
||||
LL | pub extern "C" fn foo4() -> impl Copy {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------
|
||||
| |
|
||||
| not exportable
|
||||
|
||||
error: ADT types with private fields are not exportable
|
||||
--> $DIR/exportable.rs:116:5
|
||||
|
|
||||
LL | pub struct S2 {
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: `x` is private
|
||||
--> $DIR/exportable.rs:118:9
|
||||
|
|
||||
LL | x: i32
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
8
tests/ui/attributes/export/lang-item.rs
Normal file
8
tests/ui/attributes/export/lang-item.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#![feature(no_core, lang_items, export_stable)]
|
||||
#![allow(incomplete_features)]
|
||||
#![crate_type = "sdylib"]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
//~^ ERROR lang items are not allowed in stable dylibs
|
||||
trait Sized {}
|
||||
8
tests/ui/attributes/export/lang-item.stderr
Normal file
8
tests/ui/attributes/export/lang-item.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
error: lang items are not allowed in stable dylibs
|
||||
--> $DIR/lang-item.rs:6:1
|
||||
|
|
||||
LL | #[lang = "sized"]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
5
tests/ui/feature-gates/feature-gate-export_stable.rs
Normal file
5
tests/ui/feature-gates/feature-gate-export_stable.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#![crate_type="lib"]
|
||||
|
||||
#[export_stable]
|
||||
//~^ ERROR the `#[export_stable]` attribute is an experimental feature
|
||||
pub mod a {}
|
||||
13
tests/ui/feature-gates/feature-gate-export_stable.stderr
Normal file
13
tests/ui/feature-gates/feature-gate-export_stable.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: the `#[export_stable]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-export_stable.rs:3:1
|
||||
|
|
||||
LL | #[export_stable]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #139939 <https://github.com/rust-lang/rust/issues/139939> for more information
|
||||
= help: add `#![feature(export_stable)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue