Auto merge of #147397 - Zalathar:rollup-mioe9m4, r=Zalathar
Rollup of 3 pull requests Successful merges: - rust-lang/rust#146027 (support link modifier `as-needed` for raw-dylib-elf) - rust-lang/rust#146874 (compiler: Hint at multiple crate versions if trait impl is for wrong ADT ) - rust-lang/rust#147237 ([rustdoc] Cleanup "highlight::end_expansion") r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
attr_parsing_as_needed_compatibility =
|
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 =
|
attr_parsing_bundle_needs_static =
|
||||||
linking modifier `bundle` is only compatible with `static` linking kind
|
linking modifier `bundle` is only compatible with `static` linking kind
|
||||||
|
|||||||
@@ -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::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);
|
report_unstable_modifier!(native_link_modifiers_as_needed);
|
||||||
assign_modifier(as_needed)
|
assign_modifier(as_needed)
|
||||||
}
|
}
|
||||||
@@ -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`.
|
// Do this outside of the loop so that `import_name_type` can be specified before `kind`.
|
||||||
if let Some((_, span)) = import_name_type {
|
if let Some((_, span)) = import_name_type {
|
||||||
if kind != Some(NativeLibKind::RawDylib) {
|
if !matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
|
||||||
cx.emit_err(ImportNameTypeRaw { span });
|
cx.emit_err(ImportNameTypeRaw { span });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(NativeLibKind::RawDylib) = kind
|
if let Some(NativeLibKind::RawDylib { .. }) = kind
|
||||||
&& name.as_str().contains('\0')
|
&& name.as_str().contains('\0')
|
||||||
{
|
{
|
||||||
cx.emit_err(RawDylibNoNul { span: name_span });
|
cx.emit_err(RawDylibNoNul { span: name_span });
|
||||||
@@ -315,7 +316,7 @@ impl LinkParser {
|
|||||||
cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
|
cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeLibKind::RawDylib
|
NativeLibKind::RawDylib { as_needed: None }
|
||||||
}
|
}
|
||||||
sym::link_dash_arg => {
|
sym::link_dash_arg => {
|
||||||
if !features.link_arg_attribute() {
|
if !features.link_arg_attribute() {
|
||||||
|
|||||||
@@ -1490,7 +1490,7 @@ fn print_native_static_libs(
|
|||||||
NativeLibKind::Static { bundle: None | Some(true), .. }
|
NativeLibKind::Static { bundle: None | Some(true), .. }
|
||||||
| NativeLibKind::LinkArg
|
| NativeLibKind::LinkArg
|
||||||
| NativeLibKind::WasmImportModule
|
| NativeLibKind::WasmImportModule
|
||||||
| NativeLibKind::RawDylib => None,
|
| NativeLibKind::RawDylib { .. } => None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// deduplication of consecutive repeated libraries, see rust-lang/rust#113209
|
// deduplication of consecutive repeated libraries, see rust-lang/rust#113209
|
||||||
@@ -2364,13 +2364,13 @@ fn linker_with_args(
|
|||||||
cmd.add_object(&output_path);
|
cmd.add_object(&output_path);
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
sess,
|
||||||
codegen_results.crate_info.used_libraries.iter(),
|
codegen_results.crate_info.used_libraries.iter(),
|
||||||
&raw_dylib_dir,
|
&raw_dylib_dir,
|
||||||
) {
|
) {
|
||||||
// Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
|
// 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
|
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
|
||||||
@@ -2411,13 +2411,13 @@ fn linker_with_args(
|
|||||||
cmd.add_object(&output_path);
|
cmd.add_object(&output_path);
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
sess,
|
||||||
native_libraries_from_nonstatics,
|
native_libraries_from_nonstatics,
|
||||||
&raw_dylib_dir,
|
&raw_dylib_dir,
|
||||||
) {
|
) {
|
||||||
// Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects.
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2726,7 +2726,7 @@ fn add_native_libs_from_crate(
|
|||||||
cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true))
|
cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NativeLibKind::RawDylib => {
|
NativeLibKind::RawDylib { as_needed: _ } => {
|
||||||
// Handled separately in `linker_with_args`.
|
// Handled separately in `linker_with_args`.
|
||||||
}
|
}
|
||||||
NativeLibKind::WasmImportModule => {}
|
NativeLibKind::WasmImportModule => {}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ fn collate_raw_dylibs_windows<'a>(
|
|||||||
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
|
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
|
||||||
|
|
||||||
for lib in used_libraries {
|
for lib in used_libraries {
|
||||||
if lib.kind == NativeLibKind::RawDylib {
|
if let NativeLibKind::RawDylib { .. } = lib.kind {
|
||||||
let ext = if lib.verbatim { "" } else { ".dll" };
|
let ext = if lib.verbatim { "" } else { ".dll" };
|
||||||
let name = format!("{}{}", lib.name, ext);
|
let name = format!("{}{}", lib.name, ext);
|
||||||
let imports = dylib_table.entry(name.clone()).or_default();
|
let imports = dylib_table.entry(name.clone()).or_default();
|
||||||
@@ -128,12 +128,12 @@ pub(super) fn create_raw_dylib_dll_import_libs<'a>(
|
|||||||
fn collate_raw_dylibs_elf<'a>(
|
fn collate_raw_dylibs_elf<'a>(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
used_libraries: impl IntoIterator<Item = &'a NativeLib>,
|
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.
|
// 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 {
|
for lib in used_libraries {
|
||||||
if lib.kind == NativeLibKind::RawDylib {
|
if let NativeLibKind::RawDylib { as_needed } = lib.kind {
|
||||||
let filename = if lib.verbatim {
|
let filename = if lib.verbatim {
|
||||||
lib.name.as_str().to_owned()
|
lib.name.as_str().to_owned()
|
||||||
} else {
|
} else {
|
||||||
@@ -142,17 +142,19 @@ fn collate_raw_dylibs_elf<'a>(
|
|||||||
format!("{prefix}{}{ext}", lib.name)
|
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 {
|
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();
|
sess.dcx().abort_if_errors();
|
||||||
dylib_table
|
dylib_table
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, imports)| {
|
.map(|(name, (imports, as_needed))| {
|
||||||
(name, imports.into_iter().map(|(_, import)| import.clone()).collect())
|
(name, imports.into_iter().map(|(_, import)| import.clone()).collect(), as_needed)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@@ -161,10 +163,10 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
|
|||||||
sess: &Session,
|
sess: &Session,
|
||||||
used_libraries: impl IntoIterator<Item = &'a NativeLib>,
|
used_libraries: impl IntoIterator<Item = &'a NativeLib>,
|
||||||
raw_dylib_so_dir: &Path,
|
raw_dylib_so_dir: &Path,
|
||||||
) -> Vec<String> {
|
) -> Vec<(String, bool)> {
|
||||||
collate_raw_dylibs_elf(sess, used_libraries)
|
collate_raw_dylibs_elf(sess, used_libraries)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(load_filename, raw_dylib_imports)| {
|
.map(|(load_filename, raw_dylib_imports, as_needed)| {
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
// `load_filename` is the *target/loader* filename that will end up in NEEDED.
|
// `load_filename` is the *target/loader* filename that will end up in NEEDED.
|
||||||
@@ -205,7 +207,7 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
temporary_lib_name
|
(temporary_lib_name, as_needed)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,7 +309,10 @@ pub enum NativeLibKind {
|
|||||||
},
|
},
|
||||||
/// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library.
|
/// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library.
|
||||||
/// On Linux, it refers to a generated shared library stub.
|
/// 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.
|
/// A macOS-specific kind of dynamic libraries.
|
||||||
Framework {
|
Framework {
|
||||||
/// Whether the framework will be linked only if it satisfies some undefined symbols
|
/// Whether the framework will be linked only if it satisfies some undefined symbols
|
||||||
@@ -332,11 +335,10 @@ impl NativeLibKind {
|
|||||||
NativeLibKind::Static { bundle, whole_archive } => {
|
NativeLibKind::Static { bundle, whole_archive } => {
|
||||||
bundle.is_some() || whole_archive.is_some()
|
bundle.is_some() || whole_archive.is_some()
|
||||||
}
|
}
|
||||||
NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => {
|
NativeLibKind::Dylib { as_needed }
|
||||||
as_needed.is_some()
|
| NativeLibKind::Framework { as_needed }
|
||||||
}
|
| NativeLibKind::RawDylib { as_needed } => as_needed.is_some(),
|
||||||
NativeLibKind::RawDylib
|
NativeLibKind::Unspecified
|
||||||
| NativeLibKind::Unspecified
|
|
||||||
| NativeLibKind::LinkArg
|
| NativeLibKind::LinkArg
|
||||||
| NativeLibKind::WasmImportModule => false,
|
| NativeLibKind::WasmImportModule => false,
|
||||||
}
|
}
|
||||||
@@ -349,7 +351,9 @@ impl NativeLibKind {
|
|||||||
pub fn is_dllimport(&self) -> bool {
|
pub fn is_dllimport(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified
|
NativeLibKind::Dylib { .. }
|
||||||
|
| NativeLibKind::RawDylib { .. }
|
||||||
|
| NativeLibKind::Unspecified
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ impl<'tcx> Collector<'tcx> {
|
|||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
let dll_imports = match attr.kind {
|
let dll_imports = match attr.kind {
|
||||||
NativeLibKind::RawDylib => foreign_items
|
NativeLibKind::RawDylib { .. } => foreign_items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&child_item| {
|
.map(|&child_item| {
|
||||||
self.build_dll_import(
|
self.build_dll_import(
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
|
|||||||
),
|
),
|
||||||
|
|
||||||
("as-needed", NativeLibKind::Dylib { as_needed })
|
("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(
|
cx.on_unstable_value(
|
||||||
"linking modifier `as-needed` is unstable",
|
"linking modifier `as-needed` is unstable",
|
||||||
", the `-Z unstable-options` flag must also be passed to use it",
|
", the `-Z unstable-options` flag must also be passed to use it",
|
||||||
|
|||||||
@@ -467,7 +467,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
span,
|
span,
|
||||||
leaf_trait_predicate,
|
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_remove_await(&obligation, &mut err);
|
||||||
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
|
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
|
||||||
|
|
||||||
@@ -2424,7 +2425,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
||||||
/// with the same path as `trait_ref`, a help message about
|
/// with the same path as `trait_ref`, a help message about
|
||||||
/// a probable version mismatch is added to `err`
|
/// a probable version mismatch is added to `err`
|
||||||
fn note_version_mismatch(
|
fn note_trait_version_mismatch(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
@@ -2464,15 +2465,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
impl_spans,
|
impl_spans,
|
||||||
format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
|
format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
|
||||||
);
|
);
|
||||||
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
|
self.note_two_crate_versions(trait_with_same_path, err);
|
||||||
let crate_msg =
|
|
||||||
format!("perhaps two different versions of crate `{trait_crate}` are being used?");
|
|
||||||
err.note(crate_msg);
|
|
||||||
suggested = true;
|
suggested = true;
|
||||||
}
|
}
|
||||||
suggested
|
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
|
/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
|
||||||
/// `trait_ref`.
|
/// `trait_ref`.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt::{self, Display, Write};
|
use std::fmt::{self, Display, Write};
|
||||||
use std::iter;
|
use std::{cmp, iter};
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
|
use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
|
||||||
@@ -345,33 +345,26 @@ fn end_expansion<'a, W: Write>(
|
|||||||
token_handler.pending_elems.push((Cow::Borrowed("</span>"), Some(Class::Expansion)));
|
token_handler.pending_elems.push((Cow::Borrowed("</span>"), Some(Class::Expansion)));
|
||||||
return Some(expanded_code);
|
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.
|
let skip = iter::zip(token_handler.closing_tags.as_slice(), expansion_start_tags)
|
||||||
token_handler.pending_elems.push((Cow::Borrowed("</span></span>"), Some(Class::Expansion)));
|
.position(|(tag, start_tag)| tag != start_tag)
|
||||||
return None;
|
.unwrap_or_else(|| cmp::min(token_handler.closing_tags.len(), expansion_start_tags.len()));
|
||||||
|
|
||||||
|
let tags = iter::chain(
|
||||||
|
expansion_start_tags.iter().skip(skip),
|
||||||
|
token_handler.closing_tags.iter().skip(skip),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut elem = Cow::Borrowed("</span></span>");
|
||||||
|
|
||||||
|
for (tag, _) in tags.clone() {
|
||||||
|
elem.to_mut().push_str(tag);
|
||||||
|
}
|
||||||
|
for (_, class) in tags {
|
||||||
|
write!(elem.to_mut(), "<span class=\"{}\">", class.as_html()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If tags were opened inside the expansion, we need to close them and re-open them outside
|
token_handler.pending_elems.push((elem, Some(Class::Expansion)));
|
||||||
// of the expansion span.
|
|
||||||
let mut out = String::new();
|
|
||||||
let mut end = String::new();
|
|
||||||
|
|
||||||
let mut closing_tags = token_handler.closing_tags.iter().peekable();
|
|
||||||
let mut start_closing_tags = expansion_start_tags.iter().peekable();
|
|
||||||
|
|
||||||
while let (Some(tag), Some(start_tag)) = (closing_tags.peek(), start_closing_tags.peek())
|
|
||||||
&& tag == start_tag
|
|
||||||
{
|
|
||||||
closing_tags.next();
|
|
||||||
start_closing_tags.next();
|
|
||||||
}
|
|
||||||
for (tag, class) in start_closing_tags.chain(closing_tags) {
|
|
||||||
out.push_str(tag);
|
|
||||||
end.push_str(&format!("<span class=\"{}\">", class.as_html()));
|
|
||||||
}
|
|
||||||
token_handler
|
|
||||||
.pending_elems
|
|
||||||
.push((Cow::Owned(format!("</span></span>{out}{end}")), Some(Class::Expansion)));
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
tests/run-make/duplicate-dependency/foo-v1.rs
Normal file
1
tests/run-make/duplicate-dependency/foo-v1.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub struct Foo;
|
||||||
1
tests/run-make/duplicate-dependency/foo-v2.rs
Normal file
1
tests/run-make/duplicate-dependency/foo-v2.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub struct Foo;
|
||||||
15
tests/run-make/duplicate-dependency/main.rs
Normal file
15
tests/run-make/duplicate-dependency/main.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
struct Bar;
|
||||||
|
|
||||||
|
impl From<Bar> for foo::Foo {
|
||||||
|
fn from(_: Bar) -> Self {
|
||||||
|
foo::Foo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// The user might wrongly expect this to work since From<Bar> for Foo
|
||||||
|
// implies Into<Foo> for Bar. What the user missed is that different
|
||||||
|
// versions of Foo exist in the dependency graph, and the impl is for the
|
||||||
|
// wrong version.
|
||||||
|
re_export_foo::into_foo(Bar);
|
||||||
|
}
|
||||||
24
tests/run-make/duplicate-dependency/main.stderr
Normal file
24
tests/run-make/duplicate-dependency/main.stderr
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
error[E0277]: the trait bound `re_export_foo::foo::Foo: From<Bar>` is not satisfied
|
||||||
|
--> main.rs:14:29
|
||||||
|
|
|
||||||
|
LL | re_export_foo::into_foo(Bar);
|
||||||
|
| ----------------------- ^^^ the trait `From<Bar>` is not implemented for `re_export_foo::foo::Foo`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
help: item with same name found
|
||||||
|
--> $DIR/foo-v1.rs:1:1
|
||||||
|
|
|
||||||
|
LL | pub struct Foo;
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
= note: perhaps two different versions of crate `foo` are being used?
|
||||||
|
= note: required for `Bar` to implement `Into<re_export_foo::foo::Foo>`
|
||||||
|
note: required by a bound in `into_foo`
|
||||||
|
--> $DIR/re-export-foo.rs:3:25
|
||||||
|
|
|
||||||
|
LL | pub fn into_foo(_: impl Into<foo::Foo>) {}
|
||||||
|
| ^^^^^^^^^^^^^^ required by this bound in `into_foo`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
3
tests/run-make/duplicate-dependency/re-export-foo.rs
Normal file
3
tests/run-make/duplicate-dependency/re-export-foo.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub use foo;
|
||||||
|
|
||||||
|
pub fn into_foo(_: impl Into<foo::Foo>) {}
|
||||||
45
tests/run-make/duplicate-dependency/rmake.rs
Normal file
45
tests/run-make/duplicate-dependency/rmake.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
//@ needs-target-std
|
||||||
|
|
||||||
|
use run_make_support::{Rustc, cwd, diff, rust_lib_name, rustc};
|
||||||
|
|
||||||
|
fn rustc_with_common_args() -> Rustc {
|
||||||
|
let mut rustc = rustc();
|
||||||
|
rustc.remap_path_prefix(cwd(), "$DIR");
|
||||||
|
rustc.edition("2018"); // Don't require `extern crate`
|
||||||
|
rustc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc_with_common_args()
|
||||||
|
.input("foo-v1.rs")
|
||||||
|
.crate_type("rlib")
|
||||||
|
.crate_name("foo")
|
||||||
|
.extra_filename("-v1")
|
||||||
|
.metadata("-v1")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
rustc_with_common_args()
|
||||||
|
.input("foo-v2.rs")
|
||||||
|
.crate_type("rlib")
|
||||||
|
.crate_name("foo")
|
||||||
|
.extra_filename("-v2")
|
||||||
|
.metadata("-v2")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
rustc_with_common_args()
|
||||||
|
.input("re-export-foo.rs")
|
||||||
|
.crate_type("rlib")
|
||||||
|
.extern_("foo", rust_lib_name("foo-v2"))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
let stderr = rustc_with_common_args()
|
||||||
|
.input("main.rs")
|
||||||
|
.extern_("foo", rust_lib_name("foo-v1"))
|
||||||
|
.extern_("re_export_foo", rust_lib_name("re_export_foo"))
|
||||||
|
.library_search_path(cwd())
|
||||||
|
.ui_testing()
|
||||||
|
.run_fail()
|
||||||
|
.stderr_utf8();
|
||||||
|
|
||||||
|
diff().expected_file("main.stderr").normalize(r"\\", "/").actual_text("(rustc)", &stderr).run();
|
||||||
|
}
|
||||||
43
tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs
Normal file
43
tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//@ only-elf
|
||||||
|
//@ needs-dynamic-linking
|
||||||
|
|
||||||
|
//@ only-gnu
|
||||||
|
//@ only-x86_64
|
||||||
|
//@ revisions: as_needed no_as_needed no_modifier merge_1 merge_2 merge_3 merge_4
|
||||||
|
|
||||||
|
//@ [as_needed] run-pass
|
||||||
|
//@ [no_as_needed] run-fail
|
||||||
|
//@ [no_modifier] run-pass
|
||||||
|
//@ [merge_1] run-fail
|
||||||
|
//@ [merge_2] run-fail
|
||||||
|
//@ [merge_3] run-fail
|
||||||
|
//@ [merge_4] run-pass
|
||||||
|
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(raw_dylib_elf)]
|
||||||
|
#![feature(native_link_modifiers_as_needed)]
|
||||||
|
|
||||||
|
#[cfg_attr(
|
||||||
|
as_needed,
|
||||||
|
link(name = "taiqannf1y28z2rw", kind = "raw-dylib", modifiers = "+as-needed")
|
||||||
|
)]
|
||||||
|
#[cfg_attr(
|
||||||
|
no_as_needed,
|
||||||
|
link(name = "taiqannf1y28z2rw", kind = "raw-dylib", modifiers = "-as-needed")
|
||||||
|
)]
|
||||||
|
#[cfg_attr(no_modifier, link(name = "taiqannf1y28z2rw", kind = "raw-dylib"))]
|
||||||
|
unsafe extern "C" {}
|
||||||
|
|
||||||
|
#[cfg_attr(merge_1, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
|
||||||
|
#[cfg_attr(merge_2, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
|
||||||
|
#[cfg_attr(merge_3, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
|
||||||
|
#[cfg_attr(merge_4, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
|
||||||
|
unsafe extern "C" {}
|
||||||
|
|
||||||
|
#[cfg_attr(merge_1, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
|
||||||
|
#[cfg_attr(merge_2, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
|
||||||
|
#[cfg_attr(merge_3, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "-as-needed"))]
|
||||||
|
#[cfg_attr(merge_4, link(name = "k9nm7qxoa79bg7e6", kind = "raw-dylib", modifiers = "+as-needed"))]
|
||||||
|
unsafe extern "C" {}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
Reference in New Issue
Block a user