Skip to content

Commit aa5831d

Browse files
committed
Initial support for dynamically linked crates
1 parent 69482e8 commit aa5831d

File tree

89 files changed

+1985
-191
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+1985
-191
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4011,6 +4011,7 @@ dependencies = [
40114011
"rustc_fs_util",
40124012
"rustc_hir",
40134013
"rustc_hir_analysis",
4014+
"rustc_hir_pretty",
40144015
"rustc_hir_typeck",
40154016
"rustc_incremental",
40164017
"rustc_lint",

compiler/rustc_ast/src/ast.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -3192,6 +3192,7 @@ impl Item {
31923192
pub fn opt_generics(&self) -> Option<&Generics> {
31933193
match &self.kind {
31943194
ItemKind::ExternCrate(_)
3195+
| ItemKind::ExternDynCrate(_)
31953196
| ItemKind::Use(_)
31963197
| ItemKind::Mod(_, _)
31973198
| ItemKind::ForeignMod(_)
@@ -3407,6 +3408,10 @@ pub enum ItemKind {
34073408
///
34083409
/// E.g., `extern crate foo` or `extern crate foo_bar as foo`.
34093410
ExternCrate(Option<Symbol>),
3411+
/// An extern crate with a stable interface.
3412+
///
3413+
/// E.g., `extern dyn crate foo` or `extern dyn crate foo_bar as foo`.
3414+
ExternDynCrate(Option<Symbol>),
34103415
/// A use declaration item (`use`).
34113416
///
34123417
/// E.g., `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`.
@@ -3488,13 +3493,19 @@ impl ItemKind {
34883493
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
34893494
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
34903495
| Delegation(..) | DelegationMac(..) => "a",
3491-
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
3496+
ExternCrate(..)
3497+
| ExternDynCrate(..)
3498+
| ForeignMod(..)
3499+
| MacCall(..)
3500+
| Enum(..)
3501+
| Impl { .. } => "an",
34923502
}
34933503
}
34943504

34953505
pub fn descr(&self) -> &'static str {
34963506
match self {
34973507
ItemKind::ExternCrate(..) => "extern crate",
3508+
ItemKind::ExternDynCrate(..) => "extern dyn crate",
34983509
ItemKind::Use(..) => "`use` import",
34993510
ItemKind::Static(..) => "static item",
35003511
ItemKind::Const(..) => "constant item",

compiler/rustc_ast/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ impl WalkItemKind for ItemKind {
12191219
vis: &mut impl MutVisitor,
12201220
) {
12211221
match self {
1222-
ItemKind::ExternCrate(_orig_name) => {}
1222+
ItemKind::ExternCrate(_orig_name) | ItemKind::ExternDynCrate(_orig_name) => {}
12231223
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
12241224
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
12251225
vis.visit_ty(ty);

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ impl WalkItemKind for ItemKind {
366366
visitor: &mut V,
367367
) -> V::Result {
368368
match self {
369-
ItemKind::ExternCrate(_rename) => {}
369+
ItemKind::ExternCrate(_rename) | ItemKind::ExternDynCrate(_rename) => {}
370370
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)),
371371
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
372372
try_visit!(visitor.visit_ty(ty));

compiler/rustc_ast_lowering/src/item.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
180180
i: &ItemKind,
181181
) -> hir::ItemKind<'hir> {
182182
match i {
183-
ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(*orig_name),
183+
ItemKind::ExternCrate(orig_name) | ItemKind::ExternDynCrate(orig_name) => {
184+
hir::ItemKind::ExternCrate(*orig_name)
185+
}
184186
ItemKind::Use(use_tree) => {
185187
// Start with an empty prefix.
186188
let prefix = Path { segments: ThinVec::new(), span: use_tree.span, tokens: None };
@@ -1178,7 +1180,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
11781180
// create a fake body so that the entire rest of the compiler doesn't have to deal with
11791181
// this as a special case.
11801182
return self.lower_fn_body(decl, contract, |this| {
1181-
if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) {
1183+
if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic)
1184+
|| this.tcx.is_interface_build()
1185+
{
11821186
let span = this.lower_span(span);
11831187
let empty_block = hir::Block {
11841188
hir_id: this.next_id(),

compiler/rustc_ast_passes/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,6 @@ ast_passes_where_clause_before_type_alias = where clauses are not allowed before
273273
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
274274
.remove_suggestion = remove this `where`
275275
.move_suggestion = move it to the end of the type declaration
276+
277+
ast_passes_wrong_mangling_scheme_for_extern_dyn =
278+
`extern dyn` annotation is only allowed with `v0` mangling scheme

compiler/rustc_ast_passes/src/ast_validation.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use rustc_errors::DiagCtxtHandle;
3030
use rustc_feature::Features;
3131
use rustc_parse::validate_attr;
3232
use rustc_session::Session;
33+
use rustc_session::config::SymbolManglingVersion;
3334
use rustc_session::lint::builtin::{
3435
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
3536
PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -82,6 +83,8 @@ struct AstValidator<'a> {
8283
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
8384
extern_mod_safety: Option<Safety>,
8485

86+
is_interface: bool,
87+
8588
lint_buffer: &'a mut LintBuffer,
8689
}
8790

@@ -922,7 +925,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
922925

923926
let is_intrinsic =
924927
item.attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic);
925-
if body.is_none() && !is_intrinsic {
928+
if body.is_none() && !is_intrinsic && !self.is_interface {
926929
self.dcx().emit_err(errors::FnWithoutBody {
927930
span: item.span,
928931
replace_span: self.ending_semi_or_hi(item.span),
@@ -1110,6 +1113,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11101113
});
11111114
}
11121115
}
1116+
ItemKind::ExternDynCrate(_) => {
1117+
if self.sess.opts.get_symbol_mangling_version() != SymbolManglingVersion::V0 {
1118+
self.dcx()
1119+
.emit_err(errors::WrongManglingSchemeForExternDyn { span: item.span });
1120+
}
1121+
}
11131122
_ => {}
11141123
}
11151124

@@ -1419,7 +1428,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14191428
});
14201429
}
14211430
AssocItemKind::Fn(box Fn { body, .. }) => {
1422-
if body.is_none() {
1431+
if body.is_none() && !self.is_interface {
14231432
self.dcx().emit_err(errors::AssocFnWithoutBody {
14241433
span: item.span,
14251434
replace_span: self.ending_semi_or_hi(item.span),
@@ -1669,6 +1678,7 @@ pub fn check_crate(
16691678
sess: &Session,
16701679
features: &Features,
16711680
krate: &Crate,
1681+
is_interface: bool,
16721682
lints: &mut LintBuffer,
16731683
) -> bool {
16741684
let mut validator = AstValidator {
@@ -1680,6 +1690,7 @@ pub fn check_crate(
16801690
outer_impl_trait: None,
16811691
disallow_tilde_const: Some(TildeConstReason::Item),
16821692
extern_mod_safety: None,
1693+
is_interface,
16831694
lint_buffer: lints,
16841695
};
16851696
visit::walk_crate(&mut validator, krate);

compiler/rustc_ast_passes/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -824,3 +824,10 @@ pub(crate) struct DuplicatePreciseCapturing {
824824
#[label]
825825
pub bound2: Span,
826826
}
827+
828+
#[derive(Diagnostic)]
829+
#[diag(ast_passes_wrong_mangling_scheme_for_extern_dyn)]
830+
pub(crate) struct WrongManglingSchemeForExternDyn {
831+
#[primary_span]
832+
pub span: Span,
833+
}

compiler/rustc_ast_pretty/src/pprust/state/item.rs

+25-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use itertools::{Itertools, Position};
33
use rustc_ast as ast;
44
use rustc_ast::ModKind;
55
use rustc_ast::ptr::P;
6-
use rustc_span::Ident;
6+
use rustc_span::{Ident, Symbol};
77

88
use crate::pp::Breaks::Inconsistent;
99
use crate::pprust::state::fixup::FixupContext;
@@ -148,6 +148,26 @@ impl<'a> State<'a> {
148148
self.end(); // end outer head-block
149149
}
150150

151+
fn print_extern_crate(
152+
&mut self,
153+
vis: &ast::Visibility,
154+
head: &str,
155+
ident: Ident,
156+
orig_name: Option<Symbol>,
157+
) {
158+
self.head(visibility_qualified(vis, head));
159+
if let Some(orig_name) = orig_name {
160+
self.print_name(orig_name);
161+
self.space();
162+
self.word("as");
163+
self.space();
164+
}
165+
self.print_ident(ident);
166+
self.word(";");
167+
self.end(); // end inner head-block
168+
self.end(); // end outer head-block
169+
}
170+
151171
/// Pretty-prints an item.
152172
pub(crate) fn print_item(&mut self, item: &ast::Item) {
153173
self.hardbreak_if_not_bol();
@@ -156,17 +176,10 @@ impl<'a> State<'a> {
156176
self.ann.pre(self, AnnNode::Item(item));
157177
match &item.kind {
158178
ast::ItemKind::ExternCrate(orig_name) => {
159-
self.head(visibility_qualified(&item.vis, "extern crate"));
160-
if let &Some(orig_name) = orig_name {
161-
self.print_name(orig_name);
162-
self.space();
163-
self.word("as");
164-
self.space();
165-
}
166-
self.print_ident(item.ident);
167-
self.word(";");
168-
self.end(); // end inner head-block
169-
self.end(); // end outer head-block
179+
self.print_extern_crate(&item.vis, "extern crate", item.ident, *orig_name);
180+
}
181+
ast::ItemKind::ExternDynCrate(orig_name) => {
182+
self.print_extern_crate(&item.vis, "extern dyn crate", item.ident, *orig_name);
170183
}
171184
ast::ItemKind::Use(tree) => {
172185
self.print_visibility(&item.vis);

compiler/rustc_codegen_llvm/src/back/lto.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool {
4040
| CrateType::Dylib
4141
| CrateType::Staticlib
4242
| CrateType::Cdylib
43-
| CrateType::ProcMacro => true,
43+
| CrateType::ProcMacro
44+
| CrateType::Sdylib => true,
4445
CrateType::Rlib => false,
4546
}
4647
}

compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
9595
// in the `.debug_gdb_scripts` section. For that reason, we make sure that the
9696
// section is only emitted for leaf crates.
9797
let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
98-
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => {
98+
CrateType::Executable
99+
| CrateType::Dylib
100+
| CrateType::Cdylib
101+
| CrateType::Staticlib
102+
| CrateType::Sdylib => {
99103
// These are crate types for which we will embed pretty printers since they
100104
// are treated as leaf crates.
101105
true

compiler/rustc_codegen_ssa/src/back/link.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -1154,9 +1154,10 @@ fn link_natively(
11541154
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
11551155
}
11561156
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
1157-
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
1158-
strip_with_external_utility(sess, stripcmd, out_filename, &["-x"])
1159-
}
1157+
(
1158+
Strip::Symbols,
1159+
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib,
1160+
) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]),
11601161
(Strip::Symbols, _) => {
11611162
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"])
11621163
}
@@ -1344,8 +1345,10 @@ fn add_sanitizer_libraries(
13441345
// which should be linked to both executables and dynamic libraries.
13451346
// Everywhere else the runtimes are currently distributed as static
13461347
// libraries which should be linked to executables only.
1347-
if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
1348-
&& !(sess.target.is_like_osx || sess.target.is_like_msvc)
1348+
if matches!(
1349+
crate_type,
1350+
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib
1351+
) && !(sess.target.is_like_osx || sess.target.is_like_msvc)
13491352
{
13501353
return;
13511354
}
@@ -2030,6 +2033,7 @@ fn add_late_link_args(
20302033
codegen_results: &CodegenResults,
20312034
) {
20322035
let any_dynamic_crate = crate_type == CrateType::Dylib
2036+
|| crate_type == CrateType::Sdylib
20332037
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
20342038
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
20352039
});
@@ -2818,7 +2822,11 @@ fn add_upstream_rust_crates(
28182822
}
28192823
Linkage::Dynamic => {
28202824
let src = &codegen_results.crate_info.used_crate_source[&cnum];
2821-
add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0);
2825+
let lib = match &src.dylib.as_ref() {
2826+
Some(dylib) => &dylib.0,
2827+
None => &src.sdylib.as_ref().unwrap().dylib,
2828+
};
2829+
add_dynamic_crate(cmd, sess, lib);
28222830
}
28232831
}
28242832

compiler/rustc_codegen_ssa/src/back/linker.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1800,7 +1800,7 @@ pub(crate) fn linked_symbols(
18001800
crate_type: CrateType,
18011801
) -> Vec<(String, SymbolExportKind)> {
18021802
match crate_type {
1803-
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
1803+
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (),
18041804
CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
18051805
return Vec::new();
18061806
}

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
2727
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
2828
SymbolExportLevel::C
2929
}
30-
CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust,
30+
CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust,
3131
}
3232
}
3333

compiler/rustc_codegen_ssa/src/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ impl CrateInfo {
10151015
}
10161016

10171017
let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
1018-
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
1018+
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
10191019
// These are crate types for which we invoke the linker and can embed
10201020
// NatVis visualizers.
10211021
true

compiler/rustc_driver_impl/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
371371
return early_exit();
372372
}
373373

374+
rustc_interface::export::write_interface(tcx);
375+
374376
Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend))
375377
});
376378

compiler/rustc_driver_impl/src/pretty.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,11 @@ impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> {
7171
self.tcx.nested(state, nested)
7272
}
7373

74-
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
74+
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> bool {
7575
if let pprust_hir::AnnNode::Expr(_) = node {
7676
s.popen();
7777
}
78+
true
7879
}
7980

8081
fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
@@ -154,10 +155,11 @@ impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> {
154155
self.maybe_typeck_results.set(old_maybe_typeck_results);
155156
}
156157

157-
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
158+
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) -> bool {
158159
if let pprust_hir::AnnNode::Expr(_) = node {
159160
s.popen();
160161
}
162+
true
161163
}
162164

163165
fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {

compiler/rustc_feature/src/builtin_attrs.rs

+9
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
506506
naked_functions, experimental!(naked)
507507
),
508508

509+
gated!(
510+
export, Normal, template!(Word), WarnFollowing,
511+
EncodeCrossCrate::Yes, experimental!(export)
512+
),
513+
509514
// Testing:
510515
gated!(
511516
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
@@ -1152,6 +1157,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
11521157
TEST, pattern_complexity, CrateLevel, template!(NameValueStr: "N"),
11531158
ErrorFollowing, EncodeCrossCrate::No,
11541159
),
1160+
rustc_attr!(
1161+
TEST, rustc_stable_impl_id, Normal, template!(Word),
1162+
WarnFollowing, EncodeCrossCrate::No
1163+
),
11551164
];
11561165

11571166
pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,8 @@ declare_features! (
487487
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
488488
/// Allows explicit tail calls via `become` expression.
489489
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
490+
/// Allows using `#[export]` which indicates that an item is exportable.
491+
(unstable, export, "CURRENT_RUSTC_VERSION", None),
490492
/// Allows defining `extern type`s.
491493
(unstable, extern_types, "1.23.0", Some(43467)),
492494
/// Allow using 128-bit (quad precision) floating point numbers.

0 commit comments

Comments
 (0)