mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Auto merge of #101238 - RalfJung:rollup-bzcmobj, r=RalfJung
Rollup of 7 pull requests Successful merges: - #90946 (Ignore `reference`s in "Type::inner_def_id") - #100730 (Migrate rustc_monomorphize to use SessionDiagnostic) - #100753 (translations(rustc_session): migrates `rustc_session` to use `SessionDiagnostic` - Pt. 1) - #100831 (Migrate `symbol_mangling` module to new diagnostics structs) - #101204 (rustdoc: Resugar async fn return type in `clean`, not `html`) - #101216 (Use in-page links for sanitizer docs.) - #101237 (fix into_iter on ZST) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
4fd4de7ea3
@ -3905,8 +3905,10 @@ name = "rustc_monomorphize"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
@ -4154,7 +4156,9 @@ dependencies = [
|
||||
"punycode",
|
||||
"rustc-demangle",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
@ -925,8 +925,11 @@ pub(crate) fn codegen_panic_inner<'tcx>(
|
||||
args: &[Value],
|
||||
span: Span,
|
||||
) {
|
||||
let def_id =
|
||||
fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| fx.tcx.sess.span_fatal(span, &s));
|
||||
let def_id = fx
|
||||
.tcx
|
||||
.lang_items()
|
||||
.require(lang_item)
|
||||
.unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string()));
|
||||
|
||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||
let symbol_name = fx.tcx.symbol_name(instance).name;
|
||||
|
@ -1892,7 +1892,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
||||
}
|
||||
});
|
||||
|
||||
sess.cgu_reuse_tracker.check_expected_reuse(sess.diagnostic());
|
||||
sess.cgu_reuse_tracker.check_expected_reuse(sess);
|
||||
|
||||
sess.abort_if_errors();
|
||||
|
||||
|
26
compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
Normal file
26
compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
Normal file
@ -0,0 +1,26 @@
|
||||
monomorphize_recursion_limit =
|
||||
reached the recursion limit while instantiating `{$shrunk}`
|
||||
.note = `{$def_path_str}` defined here
|
||||
|
||||
monomorphize_written_to_path = the full type name has been written to '{$path}'
|
||||
|
||||
monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
|
||||
|
||||
monomorphize_consider_type_length_limit =
|
||||
consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
|
||||
|
||||
monomorphize_fatal_error = {$error_message}
|
||||
|
||||
monomorphize_unknown_partition_strategy = unknown partitioning strategy
|
||||
|
||||
monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
|
||||
|
||||
monomorphize_unused_generic_params = item has unused generic parameters
|
||||
|
||||
monomorphize_large_assignments =
|
||||
moving {$size} bytes
|
||||
.label = value moved from here
|
||||
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
monomorphize_requires_lang_item =
|
||||
requires `{$lang_item}` lang_item
|
16
compiler/rustc_error_messages/locales/en-US/session.ftl
Normal file
16
compiler/rustc_error_messages/locales/en-US/session.ftl
Normal file
@ -0,0 +1,16 @@
|
||||
session_incorrect_cgu_reuse_type =
|
||||
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
|
||||
[one] {"at least "}
|
||||
*[other] {""}
|
||||
}`{$expected_reuse}`
|
||||
|
||||
session_cgu_not_recorded =
|
||||
CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded`
|
||||
|
||||
session_feature_gate_error = {$explain}
|
||||
|
||||
session_feature_diagnostic_for_issue =
|
||||
see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
|
||||
|
||||
session_feature_diagnostic_help =
|
||||
add `#![feature({$feature})]` to the crate attributes to enable
|
@ -0,0 +1,7 @@
|
||||
symbol_mangling_invalid_symbol_name = symbol-name({$mangled_formatted})
|
||||
|
||||
symbol_mangling_invalid_trait_item = demangling({$demangling_formatted})
|
||||
|
||||
symbol_mangling_alt_invalid_trait_item = demangling-alt({$alt_demangling_formatted})
|
||||
|
||||
symbol_mangling_invalid_def_path = def-path({$def_path})
|
@ -41,9 +41,11 @@ fluent_messages! {
|
||||
const_eval => "../locales/en-US/const_eval.ftl",
|
||||
driver => "../locales/en-US/driver.ftl",
|
||||
expand => "../locales/en-US/expand.ftl",
|
||||
session => "../locales/en-US/session.ftl",
|
||||
interface => "../locales/en-US/interface.ftl",
|
||||
infer => "../locales/en-US/infer.ftl",
|
||||
lint => "../locales/en-US/lint.ftl",
|
||||
monomorphize => "../locales/en-US/monomorphize.ftl",
|
||||
parser => "../locales/en-US/parser.ftl",
|
||||
passes => "../locales/en-US/passes.ftl",
|
||||
plugin_impl => "../locales/en-US/plugin_impl.ftl",
|
||||
@ -52,6 +54,7 @@ fluent_messages! {
|
||||
ty_utils => "../locales/en-US/ty_utils.ftl",
|
||||
typeck => "../locales/en-US/typeck.ftl",
|
||||
mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
|
||||
symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
|
||||
}
|
||||
|
||||
pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
|
||||
|
10
compiler/rustc_hir/src/errors.rs
Normal file
10
compiler/rustc_hir/src/errors.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use crate::LangItem;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub struct LangItemError(pub LangItem);
|
||||
|
||||
impl ToString for LangItemError {
|
||||
fn to_string(&self) -> String {
|
||||
format!("requires `{}` lang_item", self.0.name())
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
//! * Functions called by the compiler itself.
|
||||
|
||||
use crate::def_id::DefId;
|
||||
use crate::errors::LangItemError;
|
||||
use crate::{MethodKind, Target};
|
||||
|
||||
use rustc_ast as ast;
|
||||
@ -115,9 +116,9 @@ macro_rules! language_item_table {
|
||||
|
||||
/// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
|
||||
/// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
|
||||
/// returns an error message as a string.
|
||||
pub fn require(&self, it: LangItem) -> Result<DefId, String> {
|
||||
self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
|
||||
/// returns an error encapsulating the `LangItem`.
|
||||
pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
|
||||
self.items[it as usize].ok_or_else(|| LangItemError(it))
|
||||
}
|
||||
|
||||
/// Returns the [`DefId`]s of all lang items in a group.
|
||||
|
@ -27,6 +27,7 @@ pub mod def;
|
||||
pub mod def_path_hash_map;
|
||||
pub mod definitions;
|
||||
pub mod diagnostic_items;
|
||||
pub mod errors;
|
||||
pub use rustc_span::def_id;
|
||||
mod hir;
|
||||
pub mod hir_id;
|
||||
|
@ -18,11 +18,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Returns the `DefId` for a given `LangItem`.
|
||||
/// If not found, fatally aborts compilation.
|
||||
pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId {
|
||||
self.lang_items().require(lang_item).unwrap_or_else(|msg| {
|
||||
self.lang_items().require(lang_item).unwrap_or_else(|err| {
|
||||
if let Some(span) = span {
|
||||
self.sess.span_fatal(span, &msg)
|
||||
self.sess.span_fatal(span, err.to_string())
|
||||
} else {
|
||||
self.sess.fatal(&msg)
|
||||
self.sess.fatal(err.to_string())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -7,11 +7,13 @@ edition = "2021"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
|
||||
tracing = "0.1"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
@ -207,6 +207,8 @@ use std::iter;
|
||||
use std::ops::Range;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum MonoItemCollectionMode {
|
||||
Eager,
|
||||
@ -604,17 +606,24 @@ fn check_recursion_limit<'tcx>(
|
||||
// more than the recursion limit is assumed to be causing an
|
||||
// infinite expansion.
|
||||
if !recursion_limit.value_within_limit(adjusted_recursion_depth) {
|
||||
let def_span = tcx.def_span(def_id);
|
||||
let def_path_str = tcx.def_path_str(def_id);
|
||||
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
|
||||
let error = format!("reached the recursion limit while instantiating `{}`", shrunk);
|
||||
let mut err = tcx.sess.struct_span_fatal(span, &error);
|
||||
err.span_note(
|
||||
tcx.def_span(def_id),
|
||||
&format!("`{}` defined here", tcx.def_path_str(def_id)),
|
||||
);
|
||||
if let Some(path) = written_to_path {
|
||||
err.note(&format!("the full type name has been written to '{}'", path.display()));
|
||||
}
|
||||
err.emit()
|
||||
let mut path = PathBuf::new();
|
||||
let was_written = if written_to_path.is_some() {
|
||||
path = written_to_path.unwrap();
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
tcx.sess.emit_fatal(RecursionLimit {
|
||||
span,
|
||||
shrunk,
|
||||
def_span,
|
||||
def_path_str,
|
||||
was_written,
|
||||
path,
|
||||
});
|
||||
}
|
||||
|
||||
recursion_depths.insert(def_id, recursion_depth + 1);
|
||||
@ -642,16 +651,15 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
|
||||
// Bail out in these cases to avoid that bad user experience.
|
||||
if !tcx.type_length_limit().value_within_limit(type_length) {
|
||||
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
|
||||
let msg = format!("reached the type-length limit while instantiating `{}`", shrunk);
|
||||
let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
|
||||
if let Some(path) = written_to_path {
|
||||
diag.note(&format!("the full type name has been written to '{}'", path.display()));
|
||||
}
|
||||
diag.help(&format!(
|
||||
"consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
|
||||
type_length
|
||||
));
|
||||
diag.emit()
|
||||
let span = tcx.def_span(instance.def_id());
|
||||
let mut path = PathBuf::new();
|
||||
let was_written = if written_to_path.is_some() {
|
||||
path = written_to_path.unwrap();
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
tcx.sess.emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length });
|
||||
}
|
||||
}
|
||||
|
||||
@ -914,17 +922,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||
// but correct span? This would make the lint at least accept crate-level lint attributes.
|
||||
return;
|
||||
};
|
||||
self.tcx.struct_span_lint_hir(
|
||||
self.tcx.emit_spanned_lint(
|
||||
LARGE_ASSIGNMENTS,
|
||||
lint_root,
|
||||
source_info.span,
|
||||
|lint| {
|
||||
let mut err = lint.build(&format!("moving {} bytes", layout.size.bytes()));
|
||||
err.span_label(source_info.span, "value moved from here");
|
||||
err.note(&format!(r#"The current maximum size is {}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`"#, limit.bytes()));
|
||||
err.emit();
|
||||
LargeAssignmentsLint {
|
||||
span: source_info.span,
|
||||
size: layout.size.bytes(),
|
||||
limit: limit.bytes(),
|
||||
},
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1321,7 +1328,11 @@ impl<'v> RootCollector<'_, 'v> {
|
||||
|
||||
let start_def_id = match self.tcx.lang_items().require(LangItem::Start) {
|
||||
Ok(s) => s,
|
||||
Err(err) => self.tcx.sess.fatal(&err),
|
||||
Err(lang_item_err) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.emit_fatal(RequiresLangItem { lang_item: lang_item_err.0.name().to_string() });
|
||||
}
|
||||
};
|
||||
let main_ret_ty = self.tcx.fn_sig(main_def_id).output();
|
||||
|
||||
|
84
compiler/rustc_monomorphize/src/errors.rs
Normal file
84
compiler/rustc_monomorphize/src/errors.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_macros::{LintDiagnostic, SessionDiagnostic};
|
||||
use rustc_session::SessionDiagnostic;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(monomorphize::recursion_limit)]
|
||||
pub struct RecursionLimit {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub shrunk: String,
|
||||
#[note]
|
||||
pub def_span: Span,
|
||||
pub def_path_str: String,
|
||||
#[note(monomorphize::written_to_path)]
|
||||
pub was_written: Option<()>,
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(monomorphize::type_length_limit)]
|
||||
#[help(monomorphize::consider_type_length_limit)]
|
||||
pub struct TypeLengthLimit {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub shrunk: String,
|
||||
#[note(monomorphize::written_to_path)]
|
||||
pub was_written: Option<()>,
|
||||
pub path: PathBuf,
|
||||
pub type_length: usize,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(monomorphize::requires_lang_item)]
|
||||
pub struct RequiresLangItem {
|
||||
pub lang_item: String,
|
||||
}
|
||||
|
||||
pub struct UnusedGenericParams {
|
||||
pub span: Span,
|
||||
pub param_spans: Vec<Span>,
|
||||
pub param_names: Vec<String>,
|
||||
}
|
||||
|
||||
impl SessionDiagnostic<'_> for UnusedGenericParams {
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
sess: &'_ rustc_session::parse::ParseSess,
|
||||
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut diag = sess.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
|
||||
diag.set_span(self.span);
|
||||
for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
|
||||
// FIXME: I can figure out how to do a label with a fluent string with a fixed message,
|
||||
// or a label with a dynamic value in a hard-coded string, but I haven't figured out
|
||||
// how to combine the two. 😢
|
||||
diag.span_label(span, format!("generic parameter `{}` is unused", name));
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(monomorphize::large_assignments)]
|
||||
#[note]
|
||||
pub struct LargeAssignmentsLint {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub size: u64,
|
||||
pub limit: u64,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(monomorphize::unknown_partition_strategy)]
|
||||
pub struct UnknownPartitionStrategy;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(monomorphize::symbol_already_defined)]
|
||||
pub struct SymbolAlreadyDefined {
|
||||
#[primary_span]
|
||||
pub span: Option<Span>,
|
||||
pub symbol: String,
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
#![feature(let_else)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
@ -16,6 +18,7 @@ use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
mod collector;
|
||||
mod errors;
|
||||
mod partitioning;
|
||||
mod polymorphize;
|
||||
mod util;
|
||||
|
@ -108,6 +108,7 @@ use rustc_span::symbol::Symbol;
|
||||
|
||||
use crate::collector::InliningMap;
|
||||
use crate::collector::{self, MonoItemCollectionMode};
|
||||
use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
|
||||
|
||||
pub struct PartitioningCx<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -149,7 +150,9 @@ fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box<dyn Partitioner<'tcx>> {
|
||||
|
||||
match strategy {
|
||||
"default" => Box::new(default::DefaultPartitioning),
|
||||
_ => tcx.sess.fatal("unknown partitioning strategy"),
|
||||
_ => {
|
||||
tcx.sess.emit_fatal(UnknownPartitionStrategy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,13 +334,7 @@ where
|
||||
(span1, span2) => span1.or(span2),
|
||||
};
|
||||
|
||||
let error_message = format!("symbol `{}` is already defined", sym1);
|
||||
|
||||
if let Some(span) = span {
|
||||
tcx.sess.span_fatal(span, &error_message)
|
||||
} else {
|
||||
tcx.sess.fatal(&error_message)
|
||||
}
|
||||
tcx.sess.emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ use rustc_span::symbol::sym;
|
||||
use std::convert::TryInto;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::errors::UnusedGenericParams;
|
||||
|
||||
/// Provide implementations of queries relating to polymorphization analysis.
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
providers.unused_generic_params = unused_generic_params;
|
||||
@ -206,22 +208,23 @@ fn emit_unused_generic_params_error<'tcx>(
|
||||
_ => tcx.def_span(def_id),
|
||||
};
|
||||
|
||||
let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters");
|
||||
|
||||
let mut param_spans = Vec::new();
|
||||
let mut param_names = Vec::new();
|
||||
let mut next_generics = Some(generics);
|
||||
while let Some(generics) = next_generics {
|
||||
for param in &generics.params {
|
||||
if unused_parameters.contains(param.index).unwrap_or(false) {
|
||||
debug!(?param);
|
||||
let def_span = tcx.def_span(param.def_id);
|
||||
err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name));
|
||||
param_spans.push(def_span);
|
||||
param_names.push(param.name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
next_generics = generics.parent.map(|did| tcx.generics_of(did));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
tcx.sess.emit_err(UnusedGenericParams { span: fn_span, param_spans, param_names });
|
||||
}
|
||||
|
||||
/// Visitor used to aggregate generic parameter uses.
|
||||
|
@ -2,8 +2,13 @@
|
||||
//! compilation. This is used for incremental compilation tests and debug
|
||||
//! output.
|
||||
|
||||
use crate::errors::{CguNotRecorded, IncorrectCguReuseType};
|
||||
use crate::Session;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{self};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tracing::debug;
|
||||
|
||||
@ -14,6 +19,22 @@ pub enum CguReuse {
|
||||
PostLto,
|
||||
}
|
||||
|
||||
impl fmt::Display for CguReuse {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
CguReuse::No => write!(f, "No"),
|
||||
CguReuse::PreLto => write!(f, "PreLto "),
|
||||
CguReuse::PostLto => write!(f, "PostLto "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for CguReuse {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ComparisonKind {
|
||||
Exact,
|
||||
@ -84,7 +105,7 @@ impl CguReuseTracker {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_expected_reuse(&self, diag: &rustc_errors::Handler) {
|
||||
pub fn check_expected_reuse(&self, sess: &Session) {
|
||||
if let Some(ref data) = self.data {
|
||||
let data = data.lock().unwrap();
|
||||
|
||||
@ -98,19 +119,17 @@ impl CguReuseTracker {
|
||||
};
|
||||
|
||||
if error {
|
||||
let at_least = if at_least { "at least " } else { "" };
|
||||
let msg = format!(
|
||||
"CGU-reuse for `{cgu_user_name}` is `{actual_reuse:?}` but \
|
||||
should be {at_least}`{expected_reuse:?}`"
|
||||
);
|
||||
diag.span_err(error_span.0, &msg);
|
||||
let at_least = if at_least { 1 } else { 0 };
|
||||
IncorrectCguReuseType {
|
||||
span: error_span.0,
|
||||
cgu_user_name: &cgu_user_name,
|
||||
actual_reuse,
|
||||
expected_reuse,
|
||||
at_least,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
let msg = format!(
|
||||
"CGU-reuse for `{cgu_user_name}` (mangled: `{cgu_name}`) was \
|
||||
not recorded"
|
||||
);
|
||||
diag.span_fatal(error_span.0, &msg)
|
||||
sess.emit_fatal(CguNotRecorded { cgu_user_name, cgu_name });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
45
compiler/rustc_session/src/errors.rs
Normal file
45
compiler/rustc_session/src/errors.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use crate as rustc_session;
|
||||
use crate::cgu_reuse_tracker::CguReuse;
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_macros::SessionDiagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(session::incorrect_cgu_reuse_type)]
|
||||
pub struct IncorrectCguReuseType<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub cgu_user_name: &'a str,
|
||||
pub actual_reuse: CguReuse,
|
||||
pub expected_reuse: CguReuse,
|
||||
pub at_least: u8,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(session::cgu_not_recorded)]
|
||||
pub struct CguNotRecorded<'a> {
|
||||
pub cgu_user_name: &'a str,
|
||||
pub cgu_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(session::feature_gate_error, code = "E0658")]
|
||||
pub struct FeatureGateError<'a> {
|
||||
#[primary_span]
|
||||
pub span: MultiSpan,
|
||||
pub explain: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
#[note(session::feature_diagnostic_for_issue)]
|
||||
pub struct FeatureDiagnosticForIssue {
|
||||
pub n: NonZeroU32,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
#[help(session::feature_diagnostic_help)]
|
||||
pub struct FeatureDiagnosticHelp {
|
||||
pub feature: Symbol,
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
pub mod errors;
|
||||
|
||||
pub mod cgu_reuse_tracker;
|
||||
pub mod utils;
|
||||
|
@ -2,6 +2,7 @@
|
||||
//! It also serves as an input to the parser itself.
|
||||
|
||||
use crate::config::CheckCfg;
|
||||
use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError};
|
||||
use crate::lint::{
|
||||
builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
|
||||
};
|
||||
@ -11,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::{Lock, Lrc};
|
||||
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
|
||||
use rustc_errors::{
|
||||
error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
|
||||
fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
|
||||
DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, MultiSpan, StashKey,
|
||||
};
|
||||
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
|
||||
@ -112,7 +113,7 @@ pub fn feature_err_issue<'a>(
|
||||
.map(|err| err.cancel());
|
||||
}
|
||||
|
||||
let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
|
||||
let mut err = sess.create_err(FeatureGateError { span, explain });
|
||||
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
|
||||
err
|
||||
}
|
||||
@ -130,6 +131,8 @@ pub fn feature_warn<'a>(sess: &'a ParseSess, feature: Symbol, span: Span, explai
|
||||
///
|
||||
/// This variant allows you to control whether it is a library or language feature.
|
||||
/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub fn feature_warn_issue<'a>(
|
||||
sess: &'a ParseSess,
|
||||
feature: Symbol,
|
||||
@ -172,14 +175,12 @@ pub fn add_feature_diagnostics_for_issue<'a>(
|
||||
issue: GateIssue,
|
||||
) {
|
||||
if let Some(n) = find_feature_issue(feature, issue) {
|
||||
err.note(&format!(
|
||||
"see issue #{n} <https://github.com/rust-lang/rust/issues/{n}> for more information"
|
||||
));
|
||||
err.subdiagnostic(FeatureDiagnosticForIssue { n });
|
||||
}
|
||||
|
||||
// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
|
||||
if sess.unstable_features.is_nightly_build() {
|
||||
err.help(&format!("add `#![feature({feature})]` to the crate attributes to enable"));
|
||||
err.subdiagnostic(FeatureDiagnosticHelp { feature });
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,6 +373,8 @@ impl ParseSess {
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub fn struct_err(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
@ -380,16 +383,22 @@ impl ParseSess {
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
self.span_diagnostic.struct_warn(msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
|
||||
self.span_diagnostic.struct_fatal(msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub fn struct_diagnostic<G: EmissionGuarantee>(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
|
@ -18,3 +18,5 @@ rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
36
compiler/rustc_symbol_mangling/src/errors.rs
Normal file
36
compiler/rustc_symbol_mangling/src/errors.rs
Normal file
@ -0,0 +1,36 @@
|
||||
//! Errors emitted by symbol_mangling.
|
||||
|
||||
use rustc_macros::SessionDiagnostic;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(symbol_mangling::invalid_symbol_name)]
|
||||
pub struct InvalidSymbolName {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub mangled_formatted: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(symbol_mangling::invalid_trait_item)]
|
||||
pub struct InvalidTraitItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub demangling_formatted: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(symbol_mangling::alt_invalid_trait_item)]
|
||||
pub struct AltInvalidTraitItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub alt_demangling_formatted: String,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(symbol_mangling::invalid_def_path)]
|
||||
pub struct InvalidDefPath {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path: String,
|
||||
}
|
@ -91,6 +91,8 @@
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
@ -110,6 +112,7 @@ use tracing::debug;
|
||||
mod legacy;
|
||||
mod v0;
|
||||
|
||||
pub mod errors;
|
||||
pub mod test;
|
||||
pub mod typeid;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
//! def-path. This is used for unit testing the code that generates
|
||||
//! paths etc in all kinds of annoying scenarios.
|
||||
|
||||
use crate::errors::{AltInvalidTraitItem, InvalidDefPath, InvalidSymbolName, InvalidTraitItem};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt};
|
||||
@ -59,16 +60,27 @@ impl SymbolNamesTest<'_> {
|
||||
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)),
|
||||
);
|
||||
let mangled = tcx.symbol_name(instance);
|
||||
tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
|
||||
tcx.sess.emit_err(InvalidSymbolName {
|
||||
span: attr.span,
|
||||
mangled_formatted: format!("{mangled}"),
|
||||
});
|
||||
if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
|
||||
tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
|
||||
tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
|
||||
tcx.sess.emit_err(InvalidTraitItem {
|
||||
span: attr.span,
|
||||
demangling_formatted: format!("{demangling}"),
|
||||
});
|
||||
tcx.sess.emit_err(AltInvalidTraitItem {
|
||||
span: attr.span,
|
||||
alt_demangling_formatted: format!("{:#}", demangling),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) {
|
||||
let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id()));
|
||||
tcx.sess.span_err(attr.span, &format!("def-path({})", path));
|
||||
tcx.sess.emit_err(InvalidDefPath {
|
||||
span: attr.span,
|
||||
def_path: with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,7 +359,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
|
||||
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
|
||||
|
||||
let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| {
|
||||
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
|
||||
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string()));
|
||||
});
|
||||
|
||||
let source = tcx.type_of(impl_did);
|
||||
|
@ -266,7 +266,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
||||
None
|
||||
} else if mem::size_of::<T>() == 0 {
|
||||
// See above for why 'ptr.offset' isn't used
|
||||
self.end = self.ptr.wrapping_byte_sub(1);
|
||||
self.end = self.end.wrapping_byte_sub(1);
|
||||
|
||||
// Make up a value of this ZST.
|
||||
Some(unsafe { mem::zeroed() })
|
||||
|
@ -1104,6 +1104,12 @@ fn test_into_iter_drop_allocator() {
|
||||
assert_eq!(drop_count, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_zst() {
|
||||
for _ in vec![[0u64; 0]].into_iter() {}
|
||||
for _ in vec![[0u64; 0]; 5].into_iter().rev() {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter_specialization() {
|
||||
let src: Vec<usize> = vec![0usize; 1];
|
||||
|
@ -9,17 +9,17 @@ The tracking issues for this feature are:
|
||||
|
||||
This feature allows for use of one of following sanitizers:
|
||||
|
||||
* [AddressSanitizer][clang-asan] a fast memory error detector.
|
||||
* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides
|
||||
* [AddressSanitizer](#addresssanitizer) a fast memory error detector.
|
||||
* [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity (CFI) provides
|
||||
forward-edge control flow protection.
|
||||
* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
|
||||
* [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to
|
||||
AddressSanitizer, but based on partial hardware assistance.
|
||||
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
|
||||
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
|
||||
* [MemTagSanitizer][clang-memtag] fast memory error detector based on
|
||||
* [LeakSanitizer](#leaksanitizer) a run-time memory leak detector.
|
||||
* [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads.
|
||||
* [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on
|
||||
Armv8.5-A Memory Tagging Extension.
|
||||
* [ShadowCallStack][clang-scs] provides backward-edge control flow protection.
|
||||
* [ThreadSanitizer][clang-tsan] a fast data race detector.
|
||||
* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection.
|
||||
* [ThreadSanitizer](#threadsanitizer) a fast data race detector.
|
||||
|
||||
To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
|
||||
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
|
||||
@ -58,6 +58,8 @@ AddressSanitizer works with non-instrumented code although it will impede its
|
||||
ability to detect some bugs. It is not expected to produce false positive
|
||||
reports.
|
||||
|
||||
See the [Clang AddressSanitizer documentation][clang-asan] for more details.
|
||||
|
||||
## Examples
|
||||
|
||||
Stack buffer overflow:
|
||||
@ -204,6 +206,8 @@ tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
|
||||
|
||||
LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
|
||||
|
||||
See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
|
||||
|
||||
## Example
|
||||
|
||||
```text
|
||||
@ -430,6 +434,8 @@ HWAddressSanitizer requires `tagged-globals` target feature to instrument
|
||||
globals. To enable this target feature compile with `-C
|
||||
target-feature=+tagged-globals`
|
||||
|
||||
See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details.
|
||||
|
||||
## Example
|
||||
|
||||
Heap buffer overflow:
|
||||
@ -507,6 +513,8 @@ LeakSanitizer is supported on the following targets:
|
||||
* `x86_64-apple-darwin`
|
||||
* `x86_64-unknown-linux-gnu`
|
||||
|
||||
See the [Clang LeakSanitizer documentation][clang-lsan] for more details.
|
||||
|
||||
# MemorySanitizer
|
||||
|
||||
MemorySanitizer is detector of uninitialized reads.
|
||||
@ -521,6 +529,8 @@ MemorySanitizer requires all program code to be instrumented. C/C++ dependencies
|
||||
need to be recompiled using Clang with `-fsanitize=memory` option. Failing to
|
||||
achieve that will result in false positive reports.
|
||||
|
||||
See the [Clang MemorySanitizer documentation][clang-msan] for more details.
|
||||
|
||||
## Example
|
||||
|
||||
Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and
|
||||
@ -569,7 +579,7 @@ MemTagSanitizer is supported on the following targets:
|
||||
MemTagSanitizer requires hardware support and the `mte` target feature.
|
||||
To enable this target feature compile with `-C target-feature="+mte"`.
|
||||
|
||||
More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
|
||||
See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details.
|
||||
|
||||
# ShadowCallStack
|
||||
|
||||
@ -581,7 +591,9 @@ ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and i
|
||||
|
||||
* `aarch64-linux-android`
|
||||
|
||||
A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details.
|
||||
A runtime must be provided by the application or operating system.
|
||||
|
||||
See the [Clang ShadowCallStack documentation][clang-scs] for more details.
|
||||
|
||||
# ThreadSanitizer
|
||||
|
||||
@ -604,6 +616,8 @@ can lead to false positive reports.
|
||||
ThreadSanitizer does not support atomic fences `std::sync::atomic::fence`,
|
||||
nor synchronization performed using inline assembly code.
|
||||
|
||||
See the [Clang ThreadSanitizer documentation][clang-tsan] for more details.
|
||||
|
||||
## Example
|
||||
|
||||
```rust
|
||||
@ -673,6 +687,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
|
||||
* [HWAddressSanitizer in Clang][clang-hwasan]
|
||||
* [LeakSanitizer in Clang][clang-lsan]
|
||||
* [MemorySanitizer in Clang][clang-msan]
|
||||
* [MemTagSanitizer in LLVM][llvm-memtag]
|
||||
* [ThreadSanitizer in Clang][clang-tsan]
|
||||
|
||||
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
|
||||
@ -682,3 +697,4 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
|
||||
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
|
||||
[clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
|
||||
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
|
||||
[llvm-memtag]: https://llvm.org/docs/MemTagSanitizer.html
|
||||
|
@ -886,7 +886,10 @@ fn clean_function<'tcx>(
|
||||
// NOTE: generics must be cleaned before args
|
||||
let generics = clean_generics(generics, cx);
|
||||
let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
|
||||
let decl = clean_fn_decl_with_args(cx, sig.decl, args);
|
||||
let mut decl = clean_fn_decl_with_args(cx, sig.decl, args);
|
||||
if sig.header.is_async() {
|
||||
decl.output = decl.sugared_async_return_type();
|
||||
}
|
||||
(generics, decl)
|
||||
});
|
||||
Box::new(Function { decl, generics })
|
||||
|
@ -1310,22 +1310,19 @@ impl clean::FnDecl {
|
||||
/// <br>Used to determine line-wrapping.
|
||||
/// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
|
||||
/// necessary.
|
||||
/// * `asyncness`: Whether the function is async or not.
|
||||
pub(crate) fn full_print<'a, 'tcx: 'a>(
|
||||
&'a self,
|
||||
header_len: usize,
|
||||
indent: usize,
|
||||
asyncness: hir::IsAsync,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl fmt::Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| self.inner_full_print(header_len, indent, asyncness, f, cx))
|
||||
display_fn(move |f| self.inner_full_print(header_len, indent, f, cx))
|
||||
}
|
||||
|
||||
fn inner_full_print(
|
||||
&self,
|
||||
header_len: usize,
|
||||
indent: usize,
|
||||
asyncness: hir::IsAsync,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
cx: &Context<'_>,
|
||||
) -> fmt::Result {
|
||||
@ -1390,15 +1387,9 @@ impl clean::FnDecl {
|
||||
args_plain.push_str(", ...");
|
||||
}
|
||||
|
||||
let arrow_plain;
|
||||
let arrow = if let hir::IsAsync::Async = asyncness {
|
||||
let output = self.sugared_async_return_type();
|
||||
arrow_plain = format!("{:#}", output.print(cx));
|
||||
if f.alternate() { arrow_plain.clone() } else { format!("{}", output.print(cx)) }
|
||||
} else {
|
||||
arrow_plain = format!("{:#}", self.output.print(cx));
|
||||
if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) }
|
||||
};
|
||||
let arrow_plain = format!("{:#}", self.output.print(cx));
|
||||
let arrow =
|
||||
if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) };
|
||||
|
||||
let declaration_len = header_len + args_plain.len() + arrow_plain.len();
|
||||
let output = if declaration_len > 80 {
|
||||
|
@ -613,10 +613,10 @@ fn short_item_info(
|
||||
|
||||
// Render the list of items inside one of the sections "Trait Implementations",
|
||||
// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
|
||||
fn render_impls(
|
||||
pub(crate) fn render_impls(
|
||||
cx: &mut Context<'_>,
|
||||
w: &mut Buffer,
|
||||
impls: &[&&Impl],
|
||||
impls: &[&Impl],
|
||||
containing_item: &clean::Item,
|
||||
toggle_open_by_default: bool,
|
||||
) {
|
||||
@ -821,7 +821,7 @@ fn assoc_method(
|
||||
href = href,
|
||||
name = name,
|
||||
generics = g.print(cx),
|
||||
decl = d.full_print(header_len, indent, header.asyncness, cx),
|
||||
decl = d.full_print(header_len, indent, cx),
|
||||
notable_traits = notable_traits_decl(d, cx),
|
||||
where_clause = print_where_clause(g, cx, indent, end_newline),
|
||||
)
|
||||
@ -1025,6 +1025,47 @@ impl<'a> AssocItemLink<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
|
||||
write!(
|
||||
w,
|
||||
"<h2 id=\"{id}\" class=\"small-section-header\">\
|
||||
{title}\
|
||||
<a href=\"#{id}\" class=\"anchor\"></a>\
|
||||
</h2>"
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn render_all_impls(
|
||||
w: &mut Buffer,
|
||||
cx: &mut Context<'_>,
|
||||
containing_item: &clean::Item,
|
||||
concrete: &[&Impl],
|
||||
synthetic: &[&Impl],
|
||||
blanket_impl: &[&Impl],
|
||||
) {
|
||||
let mut impls = Buffer::empty_from(w);
|
||||
render_impls(cx, &mut impls, concrete, containing_item, true);
|
||||
let impls = impls.into_inner();
|
||||
if !impls.is_empty() {
|
||||
write_impl_section_heading(w, "Trait Implementations", "trait-implementations");
|
||||
write!(w, "<div id=\"trait-implementations-list\">{}</div>", impls);
|
||||
}
|
||||
|
||||
if !synthetic.is_empty() {
|
||||
write_impl_section_heading(w, "Auto Trait Implementations", "synthetic-implementations");
|
||||
w.write_str("<div id=\"synthetic-implementations-list\">");
|
||||
render_impls(cx, w, synthetic, containing_item, false);
|
||||
w.write_str("</div>");
|
||||
}
|
||||
|
||||
if !blanket_impl.is_empty() {
|
||||
write_impl_section_heading(w, "Blanket Implementations", "blanket-implementations");
|
||||
w.write_str("<div id=\"blanket-implementations-list\">");
|
||||
render_impls(cx, w, blanket_impl, containing_item, false);
|
||||
w.write_str("</div>");
|
||||
}
|
||||
}
|
||||
|
||||
fn render_assoc_items(
|
||||
w: &mut Buffer,
|
||||
cx: &mut Context<'_>,
|
||||
@ -1054,12 +1095,7 @@ fn render_assoc_items_inner(
|
||||
let mut tmp_buf = Buffer::empty_from(w);
|
||||
let (render_mode, id) = match what {
|
||||
AssocItemRender::All => {
|
||||
tmp_buf.write_str(
|
||||
"<h2 id=\"implementations\" class=\"small-section-header\">\
|
||||
Implementations\
|
||||
<a href=\"#implementations\" class=\"anchor\"></a>\
|
||||
</h2>",
|
||||
);
|
||||
write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
|
||||
(RenderMode::Normal, "implementations-list".to_owned())
|
||||
}
|
||||
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
|
||||
@ -1068,15 +1104,14 @@ fn render_assoc_items_inner(
|
||||
if let Some(def_id) = type_.def_id(cx.cache()) {
|
||||
cx.deref_id_map.insert(def_id, id.clone());
|
||||
}
|
||||
write!(
|
||||
tmp_buf,
|
||||
"<h2 id=\"{id}\" class=\"small-section-header\">\
|
||||
<span>Methods from {trait_}<Target = {type_}></span>\
|
||||
<a href=\"#{id}\" class=\"anchor\"></a>\
|
||||
</h2>",
|
||||
id = id,
|
||||
trait_ = trait_.print(cx),
|
||||
type_ = type_.print(cx),
|
||||
write_impl_section_heading(
|
||||
&mut tmp_buf,
|
||||
&format!(
|
||||
"<span>Methods from {trait_}<Target = {type_}></span>",
|
||||
trait_ = trait_.print(cx),
|
||||
type_ = type_.print(cx),
|
||||
),
|
||||
&id,
|
||||
);
|
||||
(RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
|
||||
}
|
||||
@ -1123,49 +1158,12 @@ fn render_assoc_items_inner(
|
||||
return;
|
||||
}
|
||||
|
||||
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
|
||||
traits.iter().partition(|t| t.inner_impl().kind.is_auto());
|
||||
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
|
||||
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
|
||||
traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
|
||||
let (blanket_impl, concrete): (Vec<&Impl>, _) =
|
||||
concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
|
||||
|
||||
let mut impls = Buffer::empty_from(w);
|
||||
render_impls(cx, &mut impls, &concrete, containing_item, true);
|
||||
let impls = impls.into_inner();
|
||||
if !impls.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"<h2 id=\"trait-implementations\" class=\"small-section-header\">\
|
||||
Trait Implementations\
|
||||
<a href=\"#trait-implementations\" class=\"anchor\"></a>\
|
||||
</h2>\
|
||||
<div id=\"trait-implementations-list\">{}</div>",
|
||||
impls
|
||||
);
|
||||
}
|
||||
|
||||
if !synthetic.is_empty() {
|
||||
w.write_str(
|
||||
"<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\
|
||||
Auto Trait Implementations\
|
||||
<a href=\"#synthetic-implementations\" class=\"anchor\"></a>\
|
||||
</h2>\
|
||||
<div id=\"synthetic-implementations-list\">",
|
||||
);
|
||||
render_impls(cx, w, &synthetic, containing_item, false);
|
||||
w.write_str("</div>");
|
||||
}
|
||||
|
||||
if !blanket_impl.is_empty() {
|
||||
w.write_str(
|
||||
"<h2 id=\"blanket-implementations\" class=\"small-section-header\">\
|
||||
Blanket Implementations\
|
||||
<a href=\"#blanket-implementations\" class=\"anchor\"></a>\
|
||||
</h2>\
|
||||
<div id=\"blanket-implementations-list\">",
|
||||
);
|
||||
render_impls(cx, w, &blanket_impl, containing_item, false);
|
||||
w.write_str("</div>");
|
||||
}
|
||||
render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1970,6 +1968,70 @@ fn small_url_encode(s: String) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sidebar_render_assoc_items(
|
||||
cx: &Context<'_>,
|
||||
out: &mut Buffer,
|
||||
id_map: &mut IdMap,
|
||||
concrete: Vec<&Impl>,
|
||||
synthetic: Vec<&Impl>,
|
||||
blanket_impl: Vec<&Impl>,
|
||||
) {
|
||||
let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
|
||||
let mut links = FxHashSet::default();
|
||||
|
||||
let mut ret = impls
|
||||
.iter()
|
||||
.filter_map(|it| {
|
||||
let trait_ = it.inner_impl().trait_.as_ref()?;
|
||||
let encoded =
|
||||
id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
|
||||
|
||||
let i_display = format!("{:#}", trait_.print(cx));
|
||||
let out = Escape(&i_display);
|
||||
let prefix = match it.inner_impl().polarity {
|
||||
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
|
||||
ty::ImplPolarity::Negative => "!",
|
||||
};
|
||||
let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
|
||||
if links.insert(generated.clone()) { Some(generated) } else { None }
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
ret.sort();
|
||||
ret
|
||||
};
|
||||
|
||||
let concrete_format = format_impls(concrete, id_map);
|
||||
let synthetic_format = format_impls(synthetic, id_map);
|
||||
let blanket_format = format_impls(blanket_impl, id_map);
|
||||
|
||||
if !concrete_format.is_empty() {
|
||||
print_sidebar_block(
|
||||
out,
|
||||
"trait-implementations",
|
||||
"Trait Implementations",
|
||||
concrete_format.iter(),
|
||||
);
|
||||
}
|
||||
|
||||
if !synthetic_format.is_empty() {
|
||||
print_sidebar_block(
|
||||
out,
|
||||
"synthetic-implementations",
|
||||
"Auto Trait Implementations",
|
||||
synthetic_format.iter(),
|
||||
);
|
||||
}
|
||||
|
||||
if !blanket_format.is_empty() {
|
||||
print_sidebar_block(
|
||||
out,
|
||||
"blanket-implementations",
|
||||
"Blanket Implementations",
|
||||
blanket_format.iter(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
|
||||
let did = it.item_id.expect_def_id();
|
||||
let cache = cx.cache();
|
||||
@ -2018,65 +2080,12 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
|
||||
sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links);
|
||||
}
|
||||
|
||||
let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
|
||||
let mut links = FxHashSet::default();
|
||||
|
||||
let mut ret = impls
|
||||
.iter()
|
||||
.filter_map(|it| {
|
||||
let trait_ = it.inner_impl().trait_.as_ref()?;
|
||||
let encoded =
|
||||
id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
|
||||
|
||||
let i_display = format!("{:#}", trait_.print(cx));
|
||||
let out = Escape(&i_display);
|
||||
let prefix = match it.inner_impl().polarity {
|
||||
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
|
||||
ty::ImplPolarity::Negative => "!",
|
||||
};
|
||||
let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
|
||||
if links.insert(generated.clone()) { Some(generated) } else { None }
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
ret.sort();
|
||||
ret
|
||||
};
|
||||
|
||||
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
|
||||
v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
|
||||
let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
|
||||
concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
|
||||
|
||||
let concrete_format = format_impls(concrete, &mut id_map);
|
||||
let synthetic_format = format_impls(synthetic, &mut id_map);
|
||||
let blanket_format = format_impls(blanket_impl, &mut id_map);
|
||||
|
||||
if !concrete_format.is_empty() {
|
||||
print_sidebar_block(
|
||||
out,
|
||||
"trait-implementations",
|
||||
"Trait Implementations",
|
||||
concrete_format.iter(),
|
||||
);
|
||||
}
|
||||
|
||||
if !synthetic_format.is_empty() {
|
||||
print_sidebar_block(
|
||||
out,
|
||||
"synthetic-implementations",
|
||||
"Auto Trait Implementations",
|
||||
synthetic_format.iter(),
|
||||
);
|
||||
}
|
||||
|
||||
if !blanket_format.is_empty() {
|
||||
print_sidebar_block(
|
||||
out,
|
||||
"blanket-implementations",
|
||||
"Blanket Implementations",
|
||||
blanket_format.iter(),
|
||||
);
|
||||
}
|
||||
sidebar_render_assoc_items(cx, out, &mut id_map, concrete, synthetic, blanket_impl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2346,9 +2355,54 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
|
||||
buf.push_str("</section>")
|
||||
}
|
||||
|
||||
/// Returns the list of implementations for the primitive reference type, filtering out any
|
||||
/// implementations that are on concrete or partially generic types, only keeping implementations
|
||||
/// of the form `impl<T> Trait for &T`.
|
||||
pub(crate) fn get_filtered_impls_for_reference<'a>(
|
||||
shared: &'a Rc<SharedContext<'_>>,
|
||||
it: &clean::Item,
|
||||
) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
|
||||
let def_id = it.item_id.expect_def_id();
|
||||
// If the reference primitive is somehow not defined, exit early.
|
||||
let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) };
|
||||
// Since there is no "direct implementation" on the reference primitive type, we filter out
|
||||
// every implementation which isn't a trait implementation.
|
||||
let traits: Vec<_> = v.iter().filter(|i| i.inner_impl().trait_.is_some()).collect();
|
||||
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
|
||||
traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
|
||||
|
||||
let (blanket_impl, concrete): (Vec<&Impl>, _) =
|
||||
concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
|
||||
// Now we keep only references over full generic types.
|
||||
let concrete: Vec<_> = concrete
|
||||
.into_iter()
|
||||
.filter(|t| match t.inner_impl().for_ {
|
||||
clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
|
||||
_ => false,
|
||||
})
|
||||
.collect();
|
||||
|
||||
(concrete, synthetic, blanket_impl)
|
||||
}
|
||||
|
||||
fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
|
||||
let mut sidebar = Buffer::new();
|
||||
sidebar_assoc_items(cx, &mut sidebar, it);
|
||||
|
||||
if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
|
||||
sidebar_assoc_items(cx, &mut sidebar, it);
|
||||
} else {
|
||||
let shared = Rc::clone(&cx.shared);
|
||||
let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
|
||||
|
||||
sidebar_render_assoc_items(
|
||||
cx,
|
||||
&mut sidebar,
|
||||
&mut IdMap::new(),
|
||||
concrete,
|
||||
synthetic,
|
||||
blanket_impl,
|
||||
);
|
||||
}
|
||||
|
||||
if !sidebar.is_empty() {
|
||||
write!(buf, "<section>{}</section>", sidebar.into_inner());
|
||||
|
@ -16,10 +16,10 @@ use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::{
|
||||
collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section,
|
||||
notable_traits_decl, render_assoc_item, render_assoc_items, render_attributes_in_code,
|
||||
render_attributes_in_pre, render_impl, render_rightside, render_stability_since_raw,
|
||||
AssocItemLink, Context, ImplRenderingParameters,
|
||||
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
|
||||
item_ty_to_section, notable_traits_decl, render_all_impls, render_assoc_item,
|
||||
render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl,
|
||||
render_rightside, render_stability_since_raw, AssocItemLink, Context, ImplRenderingParameters,
|
||||
};
|
||||
use crate::clean;
|
||||
use crate::config::ModuleSorting;
|
||||
@ -530,7 +530,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
|
||||
name = name,
|
||||
generics = f.generics.print(cx),
|
||||
where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
|
||||
decl = f.decl.full_print(header_len, 0, header.asyncness, cx),
|
||||
decl = f.decl.full_print(header_len, 0, cx),
|
||||
notable_traits = notable_traits_decl(&f.decl, cx),
|
||||
);
|
||||
});
|
||||
@ -1371,8 +1371,18 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c
|
||||
}
|
||||
|
||||
fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
|
||||
let def_id = it.item_id.expect_def_id();
|
||||
document(w, cx, it, None, HeadingOffset::H2);
|
||||
render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
|
||||
if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
|
||||
render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
|
||||
} else {
|
||||
// We handle the "reference" primitive type on its own because we only want to list
|
||||
// implementations on generic types.
|
||||
let shared = Rc::clone(&cx.shared);
|
||||
let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
|
||||
|
||||
render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl);
|
||||
}
|
||||
}
|
||||
|
||||
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
|
||||
|
36
src/test/rustdoc-json/fns/async_return.rs
Normal file
36
src/test/rustdoc-json/fns/async_return.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// edition:2021
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/101199>
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
// @is "$.index[*][?(@.name=='get_int')].inner.decl.output" '{"inner": "i32", "kind": "primitive"}'
|
||||
// @is "$.index[*][?(@.name=='get_int')].inner.header.async" false
|
||||
pub fn get_int() -> i32 {
|
||||
42
|
||||
}
|
||||
|
||||
// @is "$.index[*][?(@.name=='get_int_async')].inner.decl.output" '{"inner": "i32", "kind": "primitive"}'
|
||||
// @is "$.index[*][?(@.name=='get_int_async')].inner.header.async" true
|
||||
pub async fn get_int_async() -> i32 {
|
||||
42
|
||||
}
|
||||
|
||||
// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.kind" '"impl_trait"'
|
||||
// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.name" '"Future"'
|
||||
// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"'
|
||||
// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type" '{"inner": "i32", "kind": "primitive"}'
|
||||
// @is "$.index[*][?(@.name=='get_int_future')].inner.header.async" false
|
||||
pub fn get_int_future() -> impl Future<Output = i32> {
|
||||
async { 42 }
|
||||
}
|
||||
|
||||
// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.kind" '"impl_trait"'
|
||||
// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.name" '"Future"'
|
||||
// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"'
|
||||
// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type" '{"inner": "i32", "kind": "primitive"}'
|
||||
// @is "$.index[*][?(@.name=='get_int_future_async')].inner.header.async" true
|
||||
pub async fn get_int_future_async() -> impl Future<Output = i32> {
|
||||
async { 42 }
|
||||
}
|
37
src/test/rustdoc/primitive-reference.rs
Normal file
37
src/test/rustdoc/primitive-reference.rs
Normal file
@ -0,0 +1,37 @@
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
// @has foo/index.html
|
||||
// @has - '//h2[@id="primitives"]' 'Primitive Types'
|
||||
// @has - '//a[@href="primitive.reference.html"]' 'reference'
|
||||
// @has - '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
|
||||
// @has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
|
||||
// @has foo/primitive.reference.html
|
||||
// @has - '//a[@class="primitive"]' 'reference'
|
||||
// @has - '//span[@class="in-band"]' 'Primitive Type reference'
|
||||
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
|
||||
|
||||
// There should be only one implementation listed.
|
||||
// @count - '//*[@class="impl has-srclink"]' 1
|
||||
// @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header in-band"]' \
|
||||
// 'impl<A, B> Foo<&A> for &B'
|
||||
#[doc(primitive = "reference")]
|
||||
/// this is a test!
|
||||
mod reference {}
|
||||
|
||||
pub struct Bar;
|
||||
|
||||
// This implementation should **not** show up.
|
||||
impl<T> From<&T> for Bar {
|
||||
fn from(s: &T) -> Self {
|
||||
Bar
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Foo<T> {
|
||||
fn stuff(&self, other: &T) {}
|
||||
}
|
||||
|
||||
// This implementation should show up.
|
||||
impl<A, B> Foo<&A> for &B {}
|
@ -4,8 +4,8 @@ error: reached the type-length limit while instantiating `std::mem::drop::<Optio
|
||||
LL | pub fn drop<T>(_x: T) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
||||
= help: consider adding a `#![type_length_limit="8"]` attribute to your crate
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
||||
|
||||
error: reached the type-length limit while instantiating `<[closure@std::rt::lang_start<()...e<()>>::call_once - shim(vtable)`
|
||||
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
||||
@ -13,8 +13,8 @@ error: reached the type-length limit while instantiating `<[closure@std::rt::lan
|
||||
LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
||||
= help: consider adding a `#![type_length_limit="8"]` attribute to your crate
|
||||
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user