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_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"rustc_target",
|
"rustc_target",
|
||||||
|
"tempfile",
|
||||||
"tracing",
|
"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
|
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||||
// this as a special case.
|
// this as a special case.
|
||||||
return self.lower_fn_body(decl, contract, |this| {
|
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 span = this.lower_span(span);
|
||||||
let empty_block = hir::Block {
|
let empty_block = hir::Block {
|
||||||
hir_id: this.next_id(),
|
hir_id: this.next_id(),
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,8 @@ struct AstValidator<'a> {
|
||||||
|
|
||||||
lint_node_id: NodeId,
|
lint_node_id: NodeId,
|
||||||
|
|
||||||
|
is_sdylib_interface: bool,
|
||||||
|
|
||||||
lint_buffer: &'a mut LintBuffer,
|
lint_buffer: &'a mut LintBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -952,7 +954,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.check_defaultness(item.span, *defaultness);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
|
|
||||||
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
|
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 {
|
self.dcx().emit_err(errors::FnWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
replace_span: self.ending_semi_or_hi(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, .. }) => {
|
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||||
if body.is_none() {
|
if body.is_none() && !self.is_sdylib_interface {
|
||||||
self.dcx().emit_err(errors::AssocFnWithoutBody {
|
self.dcx().emit_err(errors::AssocFnWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
|
|
@ -1689,6 +1691,7 @@ pub fn check_crate(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
features: &Features,
|
features: &Features,
|
||||||
krate: &Crate,
|
krate: &Crate,
|
||||||
|
is_sdylib_interface: bool,
|
||||||
lints: &mut LintBuffer,
|
lints: &mut LintBuffer,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut validator = AstValidator {
|
let mut validator = AstValidator {
|
||||||
|
|
@ -1701,6 +1704,7 @@ pub fn check_crate(
|
||||||
disallow_tilde_const: Some(TildeConstReason::Item),
|
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||||
extern_mod_safety: None,
|
extern_mod_safety: None,
|
||||||
lint_node_id: CRATE_NODE_ID,
|
lint_node_id: CRATE_NODE_ID,
|
||||||
|
is_sdylib_interface,
|
||||||
lint_buffer: lints,
|
lint_buffer: lints,
|
||||||
};
|
};
|
||||||
visit::walk_crate(&mut validator, krate);
|
visit::walk_crate(&mut validator, krate);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ use std::borrow::Cow;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::token::{Token, TokenKind};
|
use rustc_ast::token::{Token, TokenKind};
|
||||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
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.
|
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
|
||||||
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
|
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,7 @@ pub struct State<'a> {
|
||||||
pub s: pp::Printer,
|
pub s: pp::Printer,
|
||||||
comments: Option<Comments<'a>>,
|
comments: Option<Comments<'a>>,
|
||||||
ann: &'a (dyn PpAnn + 'a),
|
ann: &'a (dyn PpAnn + 'a),
|
||||||
|
is_sdylib_interface: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
const INDENT_UNIT: isize = 4;
|
const INDENT_UNIT: isize = 4;
|
||||||
|
|
@ -237,9 +238,36 @@ pub fn print_crate<'a>(
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
g: &AttrIdGenerator,
|
g: &AttrIdGenerator,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut s =
|
let mut s = State {
|
||||||
State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
|
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
|
// We need to print shebang before anything else
|
||||||
// otherwise the resulting code will not compile
|
// otherwise the resulting code will not compile
|
||||||
// and shebang will be useless.
|
// and shebang will be useless.
|
||||||
|
|
@ -282,8 +310,7 @@ pub fn print_crate<'a>(
|
||||||
s.print_item(item);
|
s.print_item(item);
|
||||||
}
|
}
|
||||||
s.print_remaining_comments();
|
s.print_remaining_comments();
|
||||||
s.ann.post(&mut s, AnnNode::Crate(krate));
|
s.ann.post(s, AnnNode::Crate(krate));
|
||||||
s.s.eof()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should two consecutive tokens be printed with a space between them?
|
/// 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> {
|
impl<'a> State<'a> {
|
||||||
pub fn new() -> 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)
|
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.
|
/// Pretty-prints an item.
|
||||||
pub(crate) fn print_item(&mut self, item: &ast::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.hardbreak_if_not_bol();
|
||||||
self.maybe_print_comment(item.span.lo());
|
self.maybe_print_comment(item.span.lo());
|
||||||
self.print_outer_attributes(&item.attrs);
|
self.print_outer_attributes(&item.attrs);
|
||||||
|
|
@ -682,6 +686,13 @@ impl<'a> State<'a> {
|
||||||
self.print_contract(contract);
|
self.print_contract(contract);
|
||||||
}
|
}
|
||||||
if let Some((body, (cb, ib))) = body_cb_ib {
|
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.nbsp();
|
||||||
self.print_block_with_attrs(body, attrs, cb, ib);
|
self.print_block_with_attrs(body, attrs, cb, ib);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,11 @@ use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
|
||||||
|
|
||||||
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
|
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
|
||||||
match crate_type {
|
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,
|
CrateType::Rlib | CrateType::ProcMacro => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool {
|
||||||
| CrateType::Dylib
|
| CrateType::Dylib
|
||||||
| CrateType::Staticlib
|
| CrateType::Staticlib
|
||||||
| CrateType::Cdylib
|
| CrateType::Cdylib
|
||||||
| CrateType::ProcMacro => true,
|
| CrateType::ProcMacro
|
||||||
|
| CrateType::Sdylib => true,
|
||||||
CrateType::Rlib => false,
|
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
|
// in the `.debug_gdb_scripts` section. For that reason, we make sure that the
|
||||||
// section is only emitted for leaf crates.
|
// section is only emitted for leaf crates.
|
||||||
let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
|
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
|
// These are crate types for which we will embed pretty printers since they
|
||||||
// are treated as leaf crates.
|
// are treated as leaf crates.
|
||||||
true
|
true
|
||||||
|
|
|
||||||
|
|
@ -1053,9 +1053,10 @@ fn link_natively(
|
||||||
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
|
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
|
||||||
}
|
}
|
||||||
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
|
// 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::Symbols, _) => {
|
||||||
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"])
|
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.
|
// which should be linked to both executables and dynamic libraries.
|
||||||
// Everywhere else the runtimes are currently distributed as static
|
// Everywhere else the runtimes are currently distributed as static
|
||||||
// libraries which should be linked to executables only.
|
// libraries which should be linked to executables only.
|
||||||
if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
|
if matches!(
|
||||||
&& !(sess.target.is_like_darwin || sess.target.is_like_msvc)
|
crate_type,
|
||||||
|
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib
|
||||||
|
) && !(sess.target.is_like_darwin || sess.target.is_like_msvc)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1938,6 +1941,7 @@ fn add_late_link_args(
|
||||||
codegen_results: &CodegenResults,
|
codegen_results: &CodegenResults,
|
||||||
) {
|
) {
|
||||||
let any_dynamic_crate = crate_type == CrateType::Dylib
|
let any_dynamic_crate = crate_type == CrateType::Dylib
|
||||||
|
|| crate_type == CrateType::Sdylib
|
||||||
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
|
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
|
||||||
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
|
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1817,7 +1817,7 @@ pub(crate) fn linked_symbols(
|
||||||
crate_type: CrateType,
|
crate_type: CrateType,
|
||||||
) -> Vec<(String, SymbolExportKind)> {
|
) -> Vec<(String, SymbolExportKind)> {
|
||||||
match crate_type {
|
match crate_type {
|
||||||
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
|
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (),
|
||||||
CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
|
CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
|
||||||
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
|
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
|
||||||
SymbolExportLevel::C
|
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> {
|
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();
|
return Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +168,7 @@ fn exported_symbols_provider_local<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
_: LocalCrate,
|
_: LocalCrate,
|
||||||
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
|
) -> &'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 &[];
|
return &[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1092,7 +1092,7 @@ impl CrateInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
|
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
|
// These are crate types for which we invoke the linker and can embed
|
||||||
// NatVis visualizers.
|
// NatVis visualizers.
|
||||||
true
|
true
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ use rustc_metadata::locator;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||||
use rustc_session::config::{
|
use rustc_session::config::{
|
||||||
CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions,
|
CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType,
|
||||||
Z_OPTIONS, nightly_options, parse_target_triple,
|
UnstableOptions, Z_OPTIONS, nightly_options, parse_target_triple,
|
||||||
};
|
};
|
||||||
use rustc_session::getopts::{self, Matches};
|
use rustc_session::getopts::{self, Matches};
|
||||||
use rustc_session::lint::{Lint, LintId};
|
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_dep_info(tcx);
|
||||||
|
|
||||||
|
passes::write_interface(tcx);
|
||||||
|
|
||||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||||
&& sess.opts.output_types.len() == 1
|
&& sess.opts.output_types.len() == 1
|
||||||
{
|
{
|
||||||
|
|
@ -816,6 +818,7 @@ fn print_crate_info(
|
||||||
let supported_crate_types = CRATE_TYPES
|
let supported_crate_types = CRATE_TYPES
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type))
|
.filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type))
|
||||||
|
.filter(|(_, crate_type)| *crate_type != CrateType::Sdylib)
|
||||||
.map(|(crate_type_sym, _)| *crate_type_sym)
|
.map(|(crate_type_sym, _)| *crate_type_sym)
|
||||||
.collect::<BTreeSet<_>>();
|
.collect::<BTreeSet<_>>();
|
||||||
for supported_crate_type in supported_crate_types {
|
for supported_crate_type in supported_crate_types {
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
// Unstable attributes:
|
// Unstable attributes:
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
|
// Linking:
|
||||||
|
gated!(
|
||||||
|
export_stable, Normal, template!(Word), WarnFollowing,
|
||||||
|
EncodeCrossCrate::No, experimental!(export_stable)
|
||||||
|
),
|
||||||
|
|
||||||
// Testing:
|
// Testing:
|
||||||
gated!(
|
gated!(
|
||||||
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
|
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
|
||||||
|
|
|
||||||
|
|
@ -485,6 +485,8 @@ declare_features! (
|
||||||
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
|
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
|
||||||
/// Allows explicit tail calls via `become` expression.
|
/// Allows explicit tail calls via `become` expression.
|
||||||
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
|
(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
|
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
|
||||||
/// for functions with varargs.
|
/// for functions with varargs.
|
||||||
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
|
(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::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||||
use rustc_session::cstore::Untracked;
|
use rustc_session::cstore::Untracked;
|
||||||
use rustc_session::output::{collect_crate_types, filename_for_input};
|
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::search_paths::PathKind;
|
||||||
use rustc_session::{Limit, Session};
|
use rustc_session::{Limit, Session};
|
||||||
use rustc_span::{
|
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_target::spec::PanicStrategy;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
|
@ -237,6 +238,7 @@ fn configure_and_expand(
|
||||||
sess,
|
sess,
|
||||||
features,
|
features,
|
||||||
&krate,
|
&krate,
|
||||||
|
tcx.is_sdylib_interface_build(),
|
||||||
resolver.lint_buffer(),
|
resolver.lint_buffer(),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
@ -253,6 +255,9 @@ fn configure_and_expand(
|
||||||
sess.dcx().emit_err(errors::MixedProcMacroCrate);
|
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 {
|
if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
|
||||||
sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort);
|
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(|| {
|
pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
|
||||||
let providers = &mut Providers::default();
|
let providers = &mut Providers::default();
|
||||||
providers.analysis = analysis;
|
providers.analysis = analysis;
|
||||||
|
|
@ -930,6 +954,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
||||||
CStore::from_tcx(tcx).report_unused_deps(tcx);
|
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.par_hir_for_each_module(|module| {
|
||||||
tcx.ensure_ok().check_mod_loops(module);
|
tcx.ensure_ok().check_mod_loops(module);
|
||||||
tcx.ensure_ok().check_mod_attrs(module);
|
tcx.ensure_ok().check_mod_attrs(module);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ rustc_serialize = { path = "../rustc_serialize" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
rustc_target = { path = "../rustc_target" }
|
||||||
|
tempfile = "3.7.1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
# tidy-alphabetical-end
|
# tidy-alphabetical-end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
|
||||||
writeln!(fmt, " hash: {}", data.hash())?;
|
writeln!(fmt, " hash: {}", data.hash())?;
|
||||||
writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
|
writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
|
||||||
writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
|
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 {
|
if let Some(dylib) = dylib {
|
||||||
writeln!(fmt, " dylib: {}", dylib.0.display())?;
|
writeln!(fmt, " dylib: {}", dylib.0.display())?;
|
||||||
}
|
}
|
||||||
|
|
@ -158,6 +158,9 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
|
||||||
if let Some(rmeta) = rmeta {
|
if let Some(rmeta) = rmeta {
|
||||||
writeln!(fmt, " rmeta: {}", rmeta.0.display())?;
|
writeln!(fmt, " rmeta: {}", rmeta.0.display())?;
|
||||||
}
|
}
|
||||||
|
if let Some(sdylib_interface) = sdylib_interface {
|
||||||
|
writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,45 +88,42 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
||||||
return IndexVec::new();
|
return IndexVec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
let preferred_linkage = match ty {
|
let preferred_linkage =
|
||||||
// Generating a dylib without `-C prefer-dynamic` means that we're going
|
match ty {
|
||||||
// to try to eagerly statically link all dependencies. This is normally
|
// Generating a dylib without `-C prefer-dynamic` means that we're going
|
||||||
// done for end-product dylibs, not intermediate products.
|
// 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
|
// Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set,
|
||||||
// to statically link a cdylib or staticlib. For staticlibs we use
|
// the caller may be code-size conscious, but without it, it makes sense
|
||||||
// `-Z staticlib-prefer-dynamic` for now. This may be merged into
|
// to statically link a cdylib or staticlib. For staticlibs we use
|
||||||
// `-C prefer-dynamic` in the future.
|
// `-Z staticlib-prefer-dynamic` for now. This may be merged into
|
||||||
CrateType::Dylib | CrateType::Cdylib => {
|
// `-C prefer-dynamic` in the future.
|
||||||
if sess.opts.cg.prefer_dynamic {
|
CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
|
||||||
Linkage::Dynamic
|
if sess.opts.cg.prefer_dynamic { Linkage::Dynamic } else { Linkage::Static }
|
||||||
} else {
|
}
|
||||||
|
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
|
Linkage::Static
|
||||||
}
|
}
|
||||||
}
|
CrateType::Executable => Linkage::Dynamic,
|
||||||
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
|
// proc-macro crates are mostly cdylibs, but we also need metadata.
|
||||||
// executable will be statically linked, prefer static crate linkage.
|
CrateType::ProcMacro => Linkage::Static,
|
||||||
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.
|
// No linkage happens with rlibs, we just needed the metadata (which we
|
||||||
CrateType::ProcMacro => Linkage::Static,
|
// 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();
|
let mut unavailable_as_static = Vec::new();
|
||||||
|
|
||||||
|
|
@ -165,7 +162,9 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
||||||
|
|
||||||
let all_dylibs = || {
|
let all_dylibs = || {
|
||||||
tcx.crates(()).iter().filter(|&&cnum| {
|
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 {
|
match *kind {
|
||||||
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
|
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
|
||||||
Linkage::Static if src.rlib.is_some() => continue,
|
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 => {
|
kind => {
|
||||||
let kind = match kind {
|
let kind = match kind {
|
||||||
Linkage::Static => "rlib",
|
Linkage::Static => "rlib",
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ use std::{cmp, fmt};
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||||
use rustc_data_structures::memmap::Mmap;
|
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_data_structures::svh::Svh;
|
||||||
use rustc_errors::{DiagArgValue, IntoDiagArg};
|
use rustc_errors::{DiagArgValue, IntoDiagArg};
|
||||||
use rustc_fs_util::try_canonicalize;
|
use rustc_fs_util::try_canonicalize;
|
||||||
|
|
@ -231,6 +231,7 @@ use rustc_session::search_paths::PathKind;
|
||||||
use rustc_session::utils::CanonicalizedPath;
|
use rustc_session::utils::CanonicalizedPath;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::spec::{Target, TargetTuple};
|
use rustc_target::spec::{Target, TargetTuple};
|
||||||
|
use tempfile::Builder as TempFileBuilder;
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use crate::creader::{Library, MetadataLoader};
|
use crate::creader::{Library, MetadataLoader};
|
||||||
|
|
@ -277,6 +278,7 @@ pub(crate) enum CrateFlavor {
|
||||||
Rlib,
|
Rlib,
|
||||||
Rmeta,
|
Rmeta,
|
||||||
Dylib,
|
Dylib,
|
||||||
|
SDylib,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CrateFlavor {
|
impl fmt::Display for CrateFlavor {
|
||||||
|
|
@ -285,6 +287,7 @@ impl fmt::Display for CrateFlavor {
|
||||||
CrateFlavor::Rlib => "rlib",
|
CrateFlavor::Rlib => "rlib",
|
||||||
CrateFlavor::Rmeta => "rmeta",
|
CrateFlavor::Rmeta => "rmeta",
|
||||||
CrateFlavor::Dylib => "dylib",
|
CrateFlavor::Dylib => "dylib",
|
||||||
|
CrateFlavor::SDylib => "sdylib",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -295,6 +298,7 @@ impl IntoDiagArg for CrateFlavor {
|
||||||
CrateFlavor::Rlib => DiagArgValue::Str(Cow::Borrowed("rlib")),
|
CrateFlavor::Rlib => DiagArgValue::Str(Cow::Borrowed("rlib")),
|
||||||
CrateFlavor::Rmeta => DiagArgValue::Str(Cow::Borrowed("rmeta")),
|
CrateFlavor::Rmeta => DiagArgValue::Str(Cow::Borrowed("rmeta")),
|
||||||
CrateFlavor::Dylib => DiagArgValue::Str(Cow::Borrowed("dylib")),
|
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);
|
&format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
|
||||||
let staticlib_prefix =
|
let staticlib_prefix =
|
||||||
&format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
|
&format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
|
||||||
|
let interface_prefix = rmeta_prefix;
|
||||||
|
|
||||||
let rmeta_suffix = ".rmeta";
|
let rmeta_suffix = ".rmeta";
|
||||||
let rlib_suffix = ".rlib";
|
let rlib_suffix = ".rlib";
|
||||||
let dylib_suffix = &self.target.dll_suffix;
|
let dylib_suffix = &self.target.dll_suffix;
|
||||||
let staticlib_suffix = &self.target.staticlib_suffix;
|
let staticlib_suffix = &self.target.staticlib_suffix;
|
||||||
|
let interface_suffix = ".rs";
|
||||||
|
|
||||||
let mut candidates: FxIndexMap<_, (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>)> =
|
let mut candidates: FxIndexMap<
|
||||||
Default::default();
|
_,
|
||||||
|
(FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>),
|
||||||
|
> = Default::default();
|
||||||
|
|
||||||
// First, find all possible candidate rlibs and dylibs purely based on
|
// First, find all possible candidate rlibs and dylibs purely based on
|
||||||
// the name of the files themselves. We're trying to match against an
|
// 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),
|
(rlib_prefix.as_str(), rlib_suffix, CrateFlavor::Rlib),
|
||||||
(rmeta_prefix.as_str(), rmeta_suffix, CrateFlavor::Rmeta),
|
(rmeta_prefix.as_str(), rmeta_suffix, CrateFlavor::Rmeta),
|
||||||
(dylib_prefix, dylib_suffix, CrateFlavor::Dylib),
|
(dylib_prefix, dylib_suffix, CrateFlavor::Dylib),
|
||||||
|
(interface_prefix, interface_suffix, CrateFlavor::SDylib),
|
||||||
] {
|
] {
|
||||||
if prefix == staticlib_prefix && suffix == staticlib_suffix {
|
if prefix == staticlib_prefix && suffix == staticlib_suffix {
|
||||||
should_check_staticlibs = false;
|
should_check_staticlibs = false;
|
||||||
|
|
@ -425,7 +434,7 @@ impl<'a> CrateLocator<'a> {
|
||||||
for (hash, spf) in matches {
|
for (hash, spf) in matches {
|
||||||
info!("lib candidate: {}", spf.path.display());
|
info!("lib candidate: {}", spf.path.display());
|
||||||
|
|
||||||
let (rlibs, rmetas, dylibs) =
|
let (rlibs, rmetas, dylibs, interfaces) =
|
||||||
candidates.entry(hash.to_string()).or_default();
|
candidates.entry(hash.to_string()).or_default();
|
||||||
{
|
{
|
||||||
// As a perforamnce optimisation we canonicalize the path and skip
|
// 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::Rlib => rlibs.insert(path, search_path.kind),
|
||||||
CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
|
CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
|
||||||
CrateFlavor::Dylib => dylibs.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
|
// libraries corresponds to the crate id and hash criteria that this
|
||||||
// search is being performed for.
|
// search is being performed for.
|
||||||
let mut libraries = FxIndexMap::default();
|
let mut libraries = FxIndexMap::default();
|
||||||
for (_hash, (rlibs, rmetas, dylibs)) in candidates {
|
for (_hash, (rlibs, rmetas, dylibs, interfaces)) in candidates {
|
||||||
if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
|
if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs, interfaces)? {
|
||||||
libraries.insert(svh, lib);
|
libraries.insert(svh, lib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -508,6 +518,7 @@ impl<'a> CrateLocator<'a> {
|
||||||
rlibs: FxIndexMap<PathBuf, PathKind>,
|
rlibs: FxIndexMap<PathBuf, PathKind>,
|
||||||
rmetas: FxIndexMap<PathBuf, PathKind>,
|
rmetas: FxIndexMap<PathBuf, PathKind>,
|
||||||
dylibs: FxIndexMap<PathBuf, PathKind>,
|
dylibs: FxIndexMap<PathBuf, PathKind>,
|
||||||
|
interfaces: FxIndexMap<PathBuf, PathKind>,
|
||||||
) -> Result<Option<(Svh, Library)>, CrateError> {
|
) -> Result<Option<(Svh, Library)>, CrateError> {
|
||||||
let mut slot = None;
|
let mut slot = None;
|
||||||
// Order here matters, rmeta should come first.
|
// 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.
|
// Make sure there's at most one rlib and at most one dylib.
|
||||||
//
|
//
|
||||||
// See comment in `extract_one` below.
|
// See comment in `extract_one` below.
|
||||||
let source = CrateSource {
|
let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?;
|
||||||
rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
|
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?;
|
||||||
rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
|
let sdylib_interface = self.extract_one(interfaces, CrateFlavor::SDylib, &mut slot)?;
|
||||||
dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?,
|
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?;
|
||||||
};
|
|
||||||
Ok(slot.map(|(svh, metadata, _)| (svh, Library { source, metadata })))
|
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 {
|
fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
|
||||||
|
|
@ -550,7 +566,7 @@ impl<'a> CrateLocator<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
m: FxIndexMap<PathBuf, PathKind>,
|
m: FxIndexMap<PathBuf, PathKind>,
|
||||||
flavor: CrateFlavor,
|
flavor: CrateFlavor,
|
||||||
slot: &mut Option<(Svh, MetadataBlob, PathBuf)>,
|
slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>,
|
||||||
) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
|
) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
|
||||||
// If we are producing an rlib, and we've already loaded metadata, then
|
// 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
|
// we should not attempt to discover further crate sources (unless we're
|
||||||
|
|
@ -586,6 +602,7 @@ impl<'a> CrateLocator<'a> {
|
||||||
&lib,
|
&lib,
|
||||||
self.metadata_loader,
|
self.metadata_loader,
|
||||||
self.cfg_version,
|
self.cfg_version,
|
||||||
|
Some(self.crate_name),
|
||||||
) {
|
) {
|
||||||
Ok(blob) => {
|
Ok(blob) => {
|
||||||
if let Some(h) = self.crate_matches(&blob, &lib) {
|
if let Some(h) = self.crate_matches(&blob, &lib) {
|
||||||
|
|
@ -610,6 +627,11 @@ impl<'a> CrateLocator<'a> {
|
||||||
}
|
}
|
||||||
Err(MetadataError::LoadFailure(err)) => {
|
Err(MetadataError::LoadFailure(err)) => {
|
||||||
info!("no metadata found: {}", 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
|
// 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
|
// 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.
|
// 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));
|
return Err(CrateError::FullMetadataNotFound(self.crate_name, flavor));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*slot = Some((hash, metadata, lib.clone()));
|
*slot = Some((hash, metadata, lib.clone(), flavor));
|
||||||
}
|
}
|
||||||
ret = Some((lib, kind));
|
ret = Some((lib, kind));
|
||||||
}
|
}
|
||||||
|
|
@ -736,6 +758,7 @@ impl<'a> CrateLocator<'a> {
|
||||||
let mut rlibs = FxIndexMap::default();
|
let mut rlibs = FxIndexMap::default();
|
||||||
let mut rmetas = FxIndexMap::default();
|
let mut rmetas = FxIndexMap::default();
|
||||||
let mut dylibs = FxIndexMap::default();
|
let mut dylibs = FxIndexMap::default();
|
||||||
|
let mut sdylib_interfaces = FxIndexMap::default();
|
||||||
for loc in &self.exact_paths {
|
for loc in &self.exact_paths {
|
||||||
let loc_canon = loc.canonicalized();
|
let loc_canon = loc.canonicalized();
|
||||||
let loc_orig = loc.original();
|
let loc_orig = loc.original();
|
||||||
|
|
@ -763,6 +786,9 @@ impl<'a> CrateLocator<'a> {
|
||||||
rmetas.insert(loc_canon.clone(), PathKind::ExternFlag);
|
rmetas.insert(loc_canon.clone(), PathKind::ExternFlag);
|
||||||
continue;
|
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_prefix = self.target.dll_prefix.as_ref();
|
||||||
let dll_suffix = self.target.dll_suffix.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.
|
// 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 {
|
pub(crate) fn into_error(self, dep_root: Option<CratePaths>) -> CrateError {
|
||||||
|
|
@ -797,6 +824,7 @@ fn get_metadata_section<'p>(
|
||||||
filename: &'p Path,
|
filename: &'p Path,
|
||||||
loader: &dyn MetadataLoader,
|
loader: &dyn MetadataLoader,
|
||||||
cfg_version: &'static str,
|
cfg_version: &'static str,
|
||||||
|
crate_name: Option<Symbol>,
|
||||||
) -> Result<MetadataBlob, MetadataError<'p>> {
|
) -> Result<MetadataBlob, MetadataError<'p>> {
|
||||||
if !filename.exists() {
|
if !filename.exists() {
|
||||||
return Err(MetadataError::NotPresent(filename));
|
return Err(MetadataError::NotPresent(filename));
|
||||||
|
|
@ -805,6 +833,55 @@ fn get_metadata_section<'p>(
|
||||||
CrateFlavor::Rlib => {
|
CrateFlavor::Rlib => {
|
||||||
loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
|
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 => {
|
CrateFlavor::Dylib => {
|
||||||
let buf =
|
let buf =
|
||||||
loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
|
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
|
// Header is okay -> inflate the actual metadata
|
||||||
buf.slice(|buf| &buf[data_start..(data_start + metadata_len)])
|
buf.slice(|buf| &buf[data_start..(data_start + metadata_len)])
|
||||||
}
|
}
|
||||||
CrateFlavor::Rmeta => {
|
CrateFlavor::Rmeta => get_rmeta_metadata_section(filename)?,
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let Ok(blob) = MetadataBlob::new(raw_bytes) else {
|
let Ok(blob) = MetadataBlob::new(raw_bytes) else {
|
||||||
return Err(MetadataError::LoadFailure(format!(
|
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.
|
/// A diagnostic function for dumping crate metadata to an output stream.
|
||||||
pub fn list_file_metadata(
|
pub fn list_file_metadata(
|
||||||
target: &Target,
|
target: &Target,
|
||||||
|
|
@ -887,7 +966,7 @@ pub fn list_file_metadata(
|
||||||
cfg_version: &'static str,
|
cfg_version: &'static str,
|
||||||
) -> IoResult<()> {
|
) -> IoResult<()> {
|
||||||
let flavor = get_flavor_from_path(path);
|
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),
|
Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
|
||||||
Err(msg) => write!(out, "{msg}\n"),
|
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))
|
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>(
|
fn exported_symbols<'tcx>(
|
||||||
self,
|
self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|
|
||||||
|
|
@ -406,6 +406,8 @@ provide! { tcx, def_id, other, cdata,
|
||||||
used_crate_source => { Arc::clone(&cdata.source) }
|
used_crate_source => { Arc::clone(&cdata.source) }
|
||||||
debugger_visualizers => { cdata.get_debugger_visualizers() }
|
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 => {
|
exported_symbols => {
|
||||||
let syms = cdata.exported_symbols(tcx);
|
let syms = cdata.exported_symbols(tcx);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -673,6 +673,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
let debugger_visualizers =
|
let debugger_visualizers =
|
||||||
stat!("debugger-visualizers", || self.encode_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`.
|
// Encode exported symbols info. This is prefetched in `encode_metadata`.
|
||||||
let exported_symbols = stat!("exported-symbols", || {
|
let exported_symbols = stat!("exported-symbols", || {
|
||||||
self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE))
|
self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE))
|
||||||
|
|
@ -740,6 +745,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
traits,
|
traits,
|
||||||
impls,
|
impls,
|
||||||
incoherent_impls,
|
incoherent_impls,
|
||||||
|
exportable_items,
|
||||||
|
stable_order_of_exportable_impls,
|
||||||
exported_symbols,
|
exported_symbols,
|
||||||
interpret_alloc_index,
|
interpret_alloc_index,
|
||||||
tables,
|
tables,
|
||||||
|
|
@ -2149,6 +2156,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
self.lazy_array(&all_impls)
|
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.
|
// Encodes all symbols exported from this crate into the metadata.
|
||||||
//
|
//
|
||||||
// This pass is seeded off the reachability list calculated in the
|
// This pass is seeded off the reachability list calculated in the
|
||||||
|
|
|
||||||
|
|
@ -280,6 +280,8 @@ pub(crate) struct CrateRoot {
|
||||||
tables: LazyTables,
|
tables: LazyTables,
|
||||||
debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
|
debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
|
||||||
|
|
||||||
|
exportable_items: LazyArray<DefIndex>,
|
||||||
|
stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>,
|
||||||
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
|
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
|
||||||
|
|
||||||
syntax_contexts: SyntaxContextTable,
|
syntax_contexts: SyntaxContextTable,
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,8 @@ macro_rules! arena_types {
|
||||||
[] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
|
[] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
|
||||||
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
|
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
|
||||||
[] valtree: rustc_middle::ty::ValTreeKind<'tcx>,
|
[] 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`,
|
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
||||||
// since we need to allocate this type on both 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
|
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.
|
/// The list of symbols exported from the given crate.
|
||||||
///
|
///
|
||||||
/// - All names contained in `exported_symbols(cnum)` are guaranteed to
|
/// - All names contained in `exported_symbols(cnum)` are guaranteed to
|
||||||
|
|
|
||||||
|
|
@ -1828,9 +1828,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.crate_types()
|
self.crate_types()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| match *ty {
|
.map(|ty| match *ty {
|
||||||
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => {
|
CrateType::Executable
|
||||||
MetadataKind::None
|
| CrateType::Staticlib
|
||||||
}
|
| CrateType::Cdylib
|
||||||
|
| CrateType::Sdylib => MetadataKind::None,
|
||||||
CrateType::Rlib => MetadataKind::Uncompressed,
|
CrateType::Rlib => MetadataKind::Uncompressed,
|
||||||
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
|
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
|
||||||
})
|
})
|
||||||
|
|
@ -2133,7 +2134,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
CrateType::Executable
|
CrateType::Executable
|
||||||
| CrateType::Staticlib
|
| CrateType::Staticlib
|
||||||
| CrateType::ProcMacro
|
| CrateType::ProcMacro
|
||||||
| CrateType::Cdylib => false,
|
| CrateType::Cdylib
|
||||||
|
| CrateType::Sdylib => false,
|
||||||
|
|
||||||
// FIXME rust-lang/rust#64319, rust-lang/rust#64872:
|
// FIXME rust-lang/rust#64319, rust-lang/rust#64872:
|
||||||
// We want to block export of generics from dylibs,
|
// 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
|
&& 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> {
|
pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {
|
||||||
match self.def_kind(def_id) {
|
match self.def_kind(def_id) {
|
||||||
DefKind::Fn | DefKind::AssocFn => {}
|
DefKind::Fn | DefKind::AssocFn => {}
|
||||||
|
|
|
||||||
|
|
@ -1978,6 +1978,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
None
|
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*
|
/// Check if the given `DefId` is `#\[automatically_derived\]`, *and*
|
||||||
/// whether it was produced by expanding a builtin derive macro.
|
/// whether it was produced by expanding a builtin derive macro.
|
||||||
pub fn is_builtin_derived(self, def_id: DefId) -> bool {
|
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;
|
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);
|
let source_info = self.source_info(rustc_span::DUMMY_SP);
|
||||||
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
|
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
|
||||||
self.cfg.start_new_block().unit()
|
self.cfg.start_new_block().unit()
|
||||||
|
|
|
||||||
|
|
@ -356,6 +356,8 @@ passes_ignored_derived_impls =
|
||||||
passes_implied_feature_not_exist =
|
passes_implied_feature_not_exist =
|
||||||
feature `{$implied_by}` implying `{$feature}` does 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 =
|
passes_incorrect_do_not_recommend_args =
|
||||||
`#[diagnostic::do_not_recommend]` does not expect any arguments
|
`#[diagnostic::do_not_recommend]` does not expect any arguments
|
||||||
|
|
||||||
|
|
@ -742,6 +744,23 @@ passes_trait_impl_const_stable =
|
||||||
passes_transparent_incompatible =
|
passes_transparent_incompatible =
|
||||||
transparent {$target} cannot have other repr hints
|
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 =
|
passes_unknown_external_lang_item =
|
||||||
unknown external lang item: `{$lang_item}`
|
unknown external lang item: `{$lang_item}`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
| sym::cfg_attr
|
| sym::cfg_attr
|
||||||
| sym::cfg_trace
|
| sym::cfg_trace
|
||||||
| sym::cfg_attr_trace
|
| sym::cfg_attr_trace
|
||||||
|
| sym::export_stable // handled in `check_export`
|
||||||
// need to be fixed
|
// need to be fixed
|
||||||
| sym::cfi_encoding // FIXME(cfi_encoding)
|
| sym::cfi_encoding // FIXME(cfi_encoding)
|
||||||
| sym::pointee // FIXME(derive_coerce_pointee)
|
| 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,
|
pub at_least: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(passes_incorrect_crate_type)]
|
||||||
|
pub(crate) struct IncorrectCrateType {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(passes_useless_assignment)]
|
#[diag(passes_useless_assignment)]
|
||||||
pub(crate) struct UselessAssignment<'a> {
|
pub(crate) struct UselessAssignment<'a> {
|
||||||
|
|
@ -1919,3 +1926,50 @@ pub(crate) struct UnsupportedAttributesInWhere {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: MultiSpan,
|
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 rustc_span::Span;
|
||||||
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
|
DuplicateLangItem, IncorrectCrateType, IncorrectTarget, LangItemOnIncorrectTarget,
|
||||||
|
UnknownLangItem,
|
||||||
};
|
};
|
||||||
use crate::weak_lang_items;
|
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));
|
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;
|
pub mod abi_test;
|
||||||
mod check_attr;
|
mod check_attr;
|
||||||
|
mod check_export;
|
||||||
pub mod dead;
|
pub mod dead;
|
||||||
mod debugger_visualizer;
|
mod debugger_visualizer;
|
||||||
mod diagnostic_items;
|
mod diagnostic_items;
|
||||||
|
|
@ -54,4 +55,5 @@ pub fn provide(providers: &mut Providers) {
|
||||||
reachable::provide(providers);
|
reachable::provide(providers);
|
||||||
stability::provide(providers);
|
stability::provide(providers);
|
||||||
upvars::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 {
|
fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
|
||||||
let effective_visibilities = &tcx.effective_visibilities(());
|
let effective_visibilities = &tcx.effective_visibilities(());
|
||||||
|
|
||||||
let any_library = tcx
|
let any_library = tcx.crate_types().iter().any(|ty| {
|
||||||
.crate_types()
|
*ty == CrateType::Rlib
|
||||||
.iter()
|
|| *ty == CrateType::Dylib
|
||||||
.any(|ty| *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro);
|
|| *ty == CrateType::ProcMacro
|
||||||
|
|| *ty == CrateType::Sdylib
|
||||||
|
});
|
||||||
let mut reachable_context = ReachableContext {
|
let mut reachable_context = ReachableContext {
|
||||||
tcx,
|
tcx,
|
||||||
maybe_typeck_results: None,
|
maybe_typeck_results: None,
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
|
||||||
| CrateType::ProcMacro
|
| CrateType::ProcMacro
|
||||||
| CrateType::Cdylib
|
| CrateType::Cdylib
|
||||||
| CrateType::Executable
|
| CrateType::Executable
|
||||||
| CrateType::Staticlib => true,
|
| CrateType::Staticlib
|
||||||
|
| CrateType::Sdylib => true,
|
||||||
CrateType::Rlib => false,
|
CrateType::Rlib => false,
|
||||||
});
|
});
|
||||||
if !needs_check {
|
if !needs_check {
|
||||||
|
|
|
||||||
|
|
@ -1169,6 +1169,10 @@ impl OutputFilenames {
|
||||||
.unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
|
.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
|
/// Gets the output path where a compilation artifact of the given type
|
||||||
/// should be placed on disk.
|
/// should be placed on disk.
|
||||||
fn output_path(&self, flavor: OutputType) -> PathBuf {
|
fn output_path(&self, flavor: OutputType) -> PathBuf {
|
||||||
|
|
@ -1452,13 +1456,17 @@ pub enum CrateType {
|
||||||
Staticlib,
|
Staticlib,
|
||||||
Cdylib,
|
Cdylib,
|
||||||
ProcMacro,
|
ProcMacro,
|
||||||
|
Sdylib,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrateType {
|
impl CrateType {
|
||||||
pub fn has_metadata(self) -> bool {
|
pub fn has_metadata(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
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,
|
"cdylib" => CrateType::Cdylib,
|
||||||
"bin" => CrateType::Executable,
|
"bin" => CrateType::Executable,
|
||||||
"proc-macro" => CrateType::ProcMacro,
|
"proc-macro" => CrateType::ProcMacro,
|
||||||
|
"sdylib" => CrateType::Sdylib,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"unknown crate type: `{part}`, expected one of: \
|
"unknown crate type: `{part}`, expected one of: \
|
||||||
|
|
@ -2915,6 +2924,7 @@ impl fmt::Display for CrateType {
|
||||||
CrateType::Staticlib => "staticlib".fmt(f),
|
CrateType::Staticlib => "staticlib".fmt(f),
|
||||||
CrateType::Cdylib => "cdylib".fmt(f),
|
CrateType::Cdylib => "cdylib".fmt(f),
|
||||||
CrateType::ProcMacro => "proc-macro".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 dylib: Option<(PathBuf, PathKind)>,
|
||||||
pub rlib: Option<(PathBuf, PathKind)>,
|
pub rlib: Option<(PathBuf, PathKind)>,
|
||||||
pub rmeta: Option<(PathBuf, PathKind)>,
|
pub rmeta: Option<(PathBuf, PathKind)>,
|
||||||
|
pub sdylib_interface: Option<(PathBuf, PathKind)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrateSource {
|
impl CrateSource {
|
||||||
|
|
|
||||||
|
|
@ -2113,6 +2113,8 @@ options! {
|
||||||
"emit noalias metadata for box (default: yes)"),
|
"emit noalias metadata for box (default: yes)"),
|
||||||
branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
|
branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
|
||||||
"set options for branch target identification and pointer authentication on AArch64"),
|
"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],
|
cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
|
||||||
"instrument control-flow architecture protection"),
|
"instrument control-flow architecture protection"),
|
||||||
check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
|
check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ pub fn filename_for_input(
|
||||||
CrateType::Rlib => {
|
CrateType::Rlib => {
|
||||||
OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.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);
|
let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
|
||||||
OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{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::staticlib, CrateType::Staticlib),
|
||||||
(sym::proc_dash_macro, CrateType::ProcMacro),
|
(sym::proc_dash_macro, CrateType::ProcMacro),
|
||||||
(sym::bin, CrateType::Executable),
|
(sym::bin, CrateType::Executable),
|
||||||
|
(sym::sdylib, CrateType::Sdylib),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
|
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];
|
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
|
// 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
|
// command line, then reuse the empty `base` Vec to hold the types that
|
||||||
// will be found in crate attributes.
|
// will be found in crate attributes.
|
||||||
|
|
|
||||||
|
|
@ -914,6 +914,7 @@ symbols! {
|
||||||
explicit_generic_args_with_impl_trait,
|
explicit_generic_args_with_impl_trait,
|
||||||
explicit_tail_calls,
|
explicit_tail_calls,
|
||||||
export_name,
|
export_name,
|
||||||
|
export_stable,
|
||||||
expr,
|
expr,
|
||||||
expr_2021,
|
expr_2021,
|
||||||
expr_fragment_specifier_2024,
|
expr_fragment_specifier_2024,
|
||||||
|
|
@ -1878,6 +1879,7 @@ symbols! {
|
||||||
saturating_add,
|
saturating_add,
|
||||||
saturating_div,
|
saturating_div,
|
||||||
saturating_sub,
|
saturating_sub,
|
||||||
|
sdylib,
|
||||||
search_unbox,
|
search_unbox,
|
||||||
select_unpredictable,
|
select_unpredictable,
|
||||||
self_in_typedefs,
|
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))]
|
#![cfg_attr(bootstrap, feature(let_chains))]
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![doc(rust_logo)]
|
#![doc(rust_logo)]
|
||||||
|
#![feature(assert_matches)]
|
||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
|
|
@ -104,6 +105,7 @@ use rustc_middle::ty::{self, Instance, TyCtxt};
|
||||||
use rustc_session::config::SymbolManglingVersion;
|
use rustc_session::config::SymbolManglingVersion;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
mod export;
|
||||||
mod hashed;
|
mod hashed;
|
||||||
mod legacy;
|
mod legacy;
|
||||||
mod v0;
|
mod v0;
|
||||||
|
|
@ -296,12 +298,21 @@ fn compute_symbol_name<'tcx>(
|
||||||
tcx.symbol_mangling_version(mangling_version_crate)
|
tcx.symbol_mangling_version(mangling_version_crate)
|
||||||
};
|
};
|
||||||
|
|
||||||
let symbol = match mangling_version {
|
let symbol = match tcx.is_exportable(def_id) {
|
||||||
SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
|
true => format!(
|
||||||
SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
|
"{}.{}",
|
||||||
SymbolManglingVersion::Hashed => hashed::mangle(tcx, instance, instantiating_crate, || {
|
v0::mangle(tcx, instance, instantiating_crate, true),
|
||||||
v0::mangle(tcx, instance, instantiating_crate)
|
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!(
|
debug_assert!(
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ pub(super) fn mangle<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
instance: Instance<'tcx>,
|
instance: Instance<'tcx>,
|
||||||
instantiating_crate: Option<CrateNum>,
|
instantiating_crate: Option<CrateNum>,
|
||||||
|
is_exportable: bool,
|
||||||
) -> String {
|
) -> String {
|
||||||
let def_id = instance.def_id();
|
let def_id = instance.def_id();
|
||||||
// FIXME(eddyb) this should ideally not be needed.
|
// FIXME(eddyb) this should ideally not be needed.
|
||||||
|
|
@ -35,6 +36,7 @@ pub(super) fn mangle<'tcx>(
|
||||||
let mut cx: SymbolMangler<'_> = SymbolMangler {
|
let mut cx: SymbolMangler<'_> = SymbolMangler {
|
||||||
tcx,
|
tcx,
|
||||||
start_offset: prefix.len(),
|
start_offset: prefix.len(),
|
||||||
|
is_exportable,
|
||||||
paths: FxHashMap::default(),
|
paths: FxHashMap::default(),
|
||||||
types: FxHashMap::default(),
|
types: FxHashMap::default(),
|
||||||
consts: 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 {
|
let mut cx: SymbolMangler<'_> = SymbolMangler {
|
||||||
tcx,
|
tcx,
|
||||||
start_offset: prefix.len(),
|
start_offset: prefix.len(),
|
||||||
|
is_exportable: false,
|
||||||
paths: FxHashMap::default(),
|
paths: FxHashMap::default(),
|
||||||
types: FxHashMap::default(),
|
types: FxHashMap::default(),
|
||||||
consts: FxHashMap::default(),
|
consts: FxHashMap::default(),
|
||||||
|
|
@ -135,6 +138,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
|
||||||
let mut cx = SymbolMangler {
|
let mut cx = SymbolMangler {
|
||||||
tcx,
|
tcx,
|
||||||
start_offset: 0,
|
start_offset: 0,
|
||||||
|
is_exportable: false,
|
||||||
paths: FxHashMap::default(),
|
paths: FxHashMap::default(),
|
||||||
types: FxHashMap::default(),
|
types: FxHashMap::default(),
|
||||||
consts: FxHashMap::default(),
|
consts: FxHashMap::default(),
|
||||||
|
|
@ -163,6 +167,7 @@ struct SymbolMangler<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
binders: Vec<BinderLevel>,
|
binders: Vec<BinderLevel>,
|
||||||
out: String,
|
out: String,
|
||||||
|
is_exportable: bool,
|
||||||
|
|
||||||
/// The length of the prefix in `out` (e.g. 2 for `_R`).
|
/// The length of the prefix in `out` (e.g. 2 for `_R`).
|
||||||
start_offset: usize,
|
start_offset: usize,
|
||||||
|
|
@ -376,7 +381,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
||||||
args,
|
args,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} 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, &[])?;
|
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> {
|
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
|
||||||
self.push("C");
|
self.push("C");
|
||||||
let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
|
if !self.is_exportable {
|
||||||
self.push_disambiguator(stable_crate_id.as_u64());
|
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);
|
let name = self.tcx.crate_name(cnum);
|
||||||
self.push_ident(name.as_str());
|
self.push_ident(name.as_str());
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ ignore = [
|
||||||
"/tests/debuginfo/", # These tests are somewhat sensitive to source code layout.
|
"/tests/debuginfo/", # These tests are somewhat sensitive to source code layout.
|
||||||
"/tests/incremental/", # 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/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/run-make/translation/test.rs", # This test contains syntax errors.
|
||||||
"/tests/rustdoc/", # Some have syntax errors, some are whitespace-sensitive.
|
"/tests/rustdoc/", # Some have syntax errors, some are whitespace-sensitive.
|
||||||
"/tests/rustdoc-gui/", # Some tests are sensitive to source code layout.
|
"/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