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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
attr_parsing_as_needed_compatibility =
linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds
attr_parsing_bundle_needs_static =
linking modifier `bundle` is only compatible with `static` linking kind
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
}

(sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed }))
| (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed })) => {
| (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed }))
| (sym::as_dash_needed, Some(NativeLibKind::RawDylib { as_needed })) => {
report_unstable_modifier!(native_link_modifiers_as_needed);
assign_modifier(as_needed)
}
Expand Down Expand Up @@ -219,12 +220,12 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {

// Do this outside of the loop so that `import_name_type` can be specified before `kind`.
if let Some((_, span)) = import_name_type {
if kind != Some(NativeLibKind::RawDylib) {
if !matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
cx.emit_err(ImportNameTypeRaw { span });
}
}

if let Some(NativeLibKind::RawDylib) = kind
if let Some(NativeLibKind::RawDylib { .. }) = kind
&& name.as_str().contains('\0')
{
cx.emit_err(RawDylibNoNul { span: name_span });
Expand Down Expand Up @@ -315,7 +316,7 @@ impl LinkParser {
cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
}

NativeLibKind::RawDylib
NativeLibKind::RawDylib { as_needed: None }
}
sym::link_dash_arg => {
if !features.link_arg_attribute() {
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ fn print_native_static_libs(
NativeLibKind::Static { bundle: None | Some(true), .. }
| NativeLibKind::LinkArg
| NativeLibKind::WasmImportModule
| NativeLibKind::RawDylib => None,
| NativeLibKind::RawDylib { .. } => None,
}
})
// deduplication of consecutive repeated libraries, see rust-lang/rust#113209
Expand Down Expand Up @@ -2364,13 +2364,13 @@ fn linker_with_args(
cmd.add_object(&output_path);
}
} else {
for link_path in raw_dylib::create_raw_dylib_elf_stub_shared_objects(
for (link_path, as_needed) in raw_dylib::create_raw_dylib_elf_stub_shared_objects(
sess,
codegen_results.crate_info.used_libraries.iter(),
&raw_dylib_dir,
) {
// Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
cmd.link_dylib_by_name(&link_path, true, false);
cmd.link_dylib_by_name(&link_path, true, as_needed);
}
}
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
Expand Down Expand Up @@ -2411,13 +2411,13 @@ fn linker_with_args(
cmd.add_object(&output_path);
}
} else {
for link_path in raw_dylib::create_raw_dylib_elf_stub_shared_objects(
for (link_path, as_needed) in raw_dylib::create_raw_dylib_elf_stub_shared_objects(
sess,
native_libraries_from_nonstatics,
&raw_dylib_dir,
) {
// Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
cmd.link_dylib_by_name(&link_path, true, false);
cmd.link_dylib_by_name(&link_path, true, as_needed);
}
}

Expand Down Expand Up @@ -2726,7 +2726,7 @@ fn add_native_libs_from_crate(
cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true))
}
}
NativeLibKind::RawDylib => {
NativeLibKind::RawDylib { as_needed: _ } => {
// Handled separately in `linker_with_args`.
}
NativeLibKind::WasmImportModule => {}
Expand Down
24 changes: 13 additions & 11 deletions compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn collate_raw_dylibs_windows<'a>(
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();

for lib in used_libraries {
if lib.kind == NativeLibKind::RawDylib {
if let NativeLibKind::RawDylib { .. } = lib.kind {
let ext = if lib.verbatim { "" } else { ".dll" };
let name = format!("{}{}", lib.name, ext);
let imports = dylib_table.entry(name.clone()).or_default();
Expand Down Expand Up @@ -128,12 +128,12 @@ pub(super) fn create_raw_dylib_dll_import_libs<'a>(
fn collate_raw_dylibs_elf<'a>(
sess: &Session,
used_libraries: impl IntoIterator<Item = &'a NativeLib>,
) -> Vec<(String, Vec<DllImport>)> {
) -> Vec<(String, Vec<DllImport>, bool)> {
// Use index maps to preserve original order of imports and libraries.
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
let mut dylib_table = FxIndexMap::<String, (FxIndexMap<Symbol, &DllImport>, bool)>::default();

for lib in used_libraries {
if lib.kind == NativeLibKind::RawDylib {
if let NativeLibKind::RawDylib { as_needed } = lib.kind {
let filename = if lib.verbatim {
lib.name.as_str().to_owned()
} else {
Expand All @@ -142,17 +142,19 @@ fn collate_raw_dylibs_elf<'a>(
format!("{prefix}{}{ext}", lib.name)
};

let imports = dylib_table.entry(filename.clone()).or_default();
let (stub_imports, stub_as_needed) =
dylib_table.entry(filename.clone()).or_insert((Default::default(), true));
for import in &lib.dll_imports {
imports.insert(import.name, import);
stub_imports.insert(import.name, import);
}
*stub_as_needed = *stub_as_needed && as_needed.unwrap_or(true);
}
}
sess.dcx().abort_if_errors();
dylib_table
.into_iter()
.map(|(name, imports)| {
(name, imports.into_iter().map(|(_, import)| import.clone()).collect())
.map(|(name, (imports, as_needed))| {
(name, imports.into_iter().map(|(_, import)| import.clone()).collect(), as_needed)
})
.collect()
}
Expand All @@ -161,10 +163,10 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
sess: &Session,
used_libraries: impl IntoIterator<Item = &'a NativeLib>,
raw_dylib_so_dir: &Path,
) -> Vec<String> {
) -> Vec<(String, bool)> {
collate_raw_dylibs_elf(sess, used_libraries)
.into_iter()
.map(|(load_filename, raw_dylib_imports)| {
.map(|(load_filename, raw_dylib_imports, as_needed)| {
use std::hash::Hash;

// `load_filename` is the *target/loader* filename that will end up in NEEDED.
Expand Down Expand Up @@ -205,7 +207,7 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
});
};

temporary_lib_name
(temporary_lib_name, as_needed)
})
.collect()
}
Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ pub enum NativeLibKind {
},
/// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library.
/// On Linux, it refers to a generated shared library stub.
RawDylib,
RawDylib {
/// Whether the dynamic library will be linked only if it satisfies some undefined symbols
as_needed: Option<bool>,
},
/// A macOS-specific kind of dynamic libraries.
Framework {
/// Whether the framework will be linked only if it satisfies some undefined symbols
Expand All @@ -332,11 +335,10 @@ impl NativeLibKind {
NativeLibKind::Static { bundle, whole_archive } => {
bundle.is_some() || whole_archive.is_some()
}
NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => {
as_needed.is_some()
}
NativeLibKind::RawDylib
| NativeLibKind::Unspecified
NativeLibKind::Dylib { as_needed }
| NativeLibKind::Framework { as_needed }
| NativeLibKind::RawDylib { as_needed } => as_needed.is_some(),
NativeLibKind::Unspecified
| NativeLibKind::LinkArg
| NativeLibKind::WasmImportModule => false,
}
Expand All @@ -349,7 +351,9 @@ impl NativeLibKind {
pub fn is_dllimport(&self) -> bool {
matches!(
self,
NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified
NativeLibKind::Dylib { .. }
| NativeLibKind::RawDylib { .. }
| NativeLibKind::Unspecified
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ impl<'tcx> Collector<'tcx> {
.flatten()
{
let dll_imports = match attr.kind {
NativeLibKind::RawDylib => foreign_items
NativeLibKind::RawDylib { .. } => foreign_items
.iter()
.map(|&child_item| {
self.build_dll_import(
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_session/src/config/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
),

("as-needed", NativeLibKind::Dylib { as_needed })
| ("as-needed", NativeLibKind::Framework { as_needed }) => {
| ("as-needed", NativeLibKind::Framework { as_needed })
| ("as-needed", NativeLibKind::RawDylib { as_needed }) => {
cx.on_unstable_value(
"linking modifier `as-needed` is unstable",
", the `-Z unstable-options` flag must also be passed to use it",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
span,
leaf_trait_predicate,
);
self.note_version_mismatch(&mut err, leaf_trait_predicate);
self.note_trait_version_mismatch(&mut err, leaf_trait_predicate);
self.note_adt_version_mismatch(&mut err, leaf_trait_predicate);
self.suggest_remove_await(&obligation, &mut err);
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);

Expand Down Expand Up @@ -2424,7 +2425,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
/// with the same path as `trait_ref`, a help message about
/// a probable version mismatch is added to `err`
fn note_version_mismatch(
fn note_trait_version_mismatch(
&self,
err: &mut Diag<'_>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
Expand Down Expand Up @@ -2464,15 +2465,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
impl_spans,
format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
);
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
let crate_msg =
format!("perhaps two different versions of crate `{trait_crate}` are being used?");
err.note(crate_msg);
self.note_two_crate_versions(trait_with_same_path, err);
suggested = true;
}
suggested
}

fn note_two_crate_versions(&self, did: DefId, err: &mut Diag<'_>) {
let crate_name = self.tcx.crate_name(did.krate);
let crate_msg =
format!("perhaps two different versions of crate `{crate_name}` are being used?");
err.note(crate_msg);
}

fn note_adt_version_mismatch(
&self,
err: &mut Diag<'_>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
let ty::Adt(impl_self_def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind()
else {
return;
};

let impl_self_did = impl_self_def.did();

// We only want to warn about different versions of a dependency.
// If no dependency is involved, bail.
if impl_self_did.krate == LOCAL_CRATE {
return;
}

let impl_self_path = self.comparable_path(impl_self_did);
let impl_self_crate_name = self.tcx.crate_name(impl_self_did.krate);
let similar_items: UnordSet<_> = self
.tcx
.visible_parent_map(())
.items()
.filter_map(|(&item, _)| {
// If we found ourselves, ignore.
if impl_self_did == item {
return None;
}
// We only want to warn about different versions of a dependency.
// Ignore items from our own crate.
if item.krate == LOCAL_CRATE {
return None;
}
// We want to warn about different versions of a dependency.
// So make sure the crate names are the same.
if impl_self_crate_name != self.tcx.crate_name(item.krate) {
return None;
}
// Filter out e.g. constructors that often have the same path
// str as the relevant ADT.
if !self.tcx.def_kind(item).is_adt() {
return None;
}
let path = self.comparable_path(item);
// We don't know if our item or the one we found is the re-exported one.
// Check both cases.
let is_similar = path.ends_with(&impl_self_path) || impl_self_path.ends_with(&path);
is_similar.then_some((item, path))
})
.collect();

let mut similar_items =
similar_items.into_items().into_sorted_stable_ord_by_key(|(_, path)| path);
similar_items.dedup();

for (similar_item, _) in similar_items {
err.span_help(self.tcx.def_span(similar_item), "item with same name found");
self.note_two_crate_versions(similar_item, err);
}
}

/// Add a `::` prefix when comparing paths so that paths with just one item
/// like "Foo" does not equal the end of "OtherFoo".
fn comparable_path(&self, did: DefId) -> String {
format!("::{}", self.tcx.def_path_str(did))
}

/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
/// `trait_ref`.
///
Expand Down
39 changes: 16 additions & 23 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use std::borrow::Cow;
use std::collections::VecDeque;
use std::fmt::{self, Display, Write};
use std::iter;
use std::{cmp, iter};

use rustc_data_structures::fx::FxIndexMap;
use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
Expand Down Expand Up @@ -345,33 +345,26 @@ fn end_expansion<'a, W: Write>(
token_handler.pending_elems.push((Cow::Borrowed("</span>"), Some(Class::Expansion)));
return Some(expanded_code);
}
if expansion_start_tags.is_empty() && token_handler.closing_tags.is_empty() {
// No need tag opened so we can just close expansion.
token_handler.pending_elems.push((Cow::Borrowed("</span></span>"), Some(Class::Expansion)));
return None;
}

// If tags were opened inside the expansion, we need to close them and re-open them outside
// of the expansion span.
let mut out = String::new();
let mut end = String::new();
let skip = iter::zip(token_handler.closing_tags.as_slice(), expansion_start_tags)
.position(|(tag, start_tag)| tag != start_tag)
.unwrap_or_else(|| cmp::min(token_handler.closing_tags.len(), expansion_start_tags.len()));

let mut closing_tags = token_handler.closing_tags.iter().peekable();
let mut start_closing_tags = expansion_start_tags.iter().peekable();
let tags = iter::chain(
expansion_start_tags.iter().skip(skip),
token_handler.closing_tags.iter().skip(skip),
);

while let (Some(tag), Some(start_tag)) = (closing_tags.peek(), start_closing_tags.peek())
&& tag == start_tag
{
closing_tags.next();
start_closing_tags.next();
let mut elem = Cow::Borrowed("</span></span>");

for (tag, _) in tags.clone() {
elem.to_mut().push_str(tag);
}
for (tag, class) in start_closing_tags.chain(closing_tags) {
out.push_str(tag);
end.push_str(&format!("<span class=\"{}\">", class.as_html()));
for (_, class) in tags {
write!(elem.to_mut(), "<span class=\"{}\">", class.as_html()).unwrap();
}
token_handler
.pending_elems
.push((Cow::Owned(format!("</span></span>{out}{end}")), Some(Class::Expansion)));

token_handler.pending_elems.push((elem, Some(Class::Expansion)));
None
}

Expand Down
1 change: 1 addition & 0 deletions tests/run-make/duplicate-dependency/foo-v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub struct Foo;
1 change: 1 addition & 0 deletions tests/run-make/duplicate-dependency/foo-v2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub struct Foo;
Loading
Loading