Auto merge of #148100 - matthiaskrgr:rollup-vrd4wy8, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - rust-lang/rust#143361 (Stop passing resolver disambiguator state to AST lowering.) - rust-lang/rust#148000 (Improvements to attribute suggestions) - rust-lang/rust#148007 (chore: Update to the latest annotate-snippets) - rust-lang/rust#148088 (compiletest: Simplify passing arguments to spawned test threads) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
34
Cargo.lock
34
Cargo.lock
@@ -75,7 +75,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.12.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47224528f74de27d1d06aad6a5dda4f865b6ebe2e56c538943d746a7270cb67e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -136,7 +146,7 @@ dependencies = [
|
||||
"anstyle-lossy",
|
||||
"anstyle-parse",
|
||||
"html-escape",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -677,7 +687,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"termcolor",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -808,7 +818,7 @@ dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -1485,7 +1495,7 @@ version = "0.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1887,7 +1897,7 @@ dependencies = [
|
||||
"console",
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
@@ -3756,7 +3766,7 @@ dependencies = [
|
||||
name = "rustc_errors"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.11.5",
|
||||
"annotate-snippets 0.12.7",
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"derive_setters",
|
||||
@@ -4331,7 +4341,7 @@ dependencies = [
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
"unicode-normalization",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4590,7 +4600,7 @@ dependencies = [
|
||||
"sha1",
|
||||
"sha2",
|
||||
"tracing",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5936,9 +5946,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -6223,7 +6233,7 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.2",
|
||||
"wasm-encoder 0.240.0",
|
||||
]
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_hir::{HirId, Target, find_attr};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
@@ -461,7 +462,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
for (idx, arg) in args.iter().cloned().enumerate() {
|
||||
if legacy_args_idx.contains(&idx) {
|
||||
let node_id = self.next_node_id();
|
||||
self.create_def(node_id, None, DefKind::AnonConst, f.span);
|
||||
self.create_def(
|
||||
node_id,
|
||||
None,
|
||||
DefKind::AnonConst,
|
||||
DefPathData::LateAnonConst,
|
||||
f.span,
|
||||
);
|
||||
let mut visitor = WillCreateDefIdsVisitor {};
|
||||
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
|
||||
Box::new(Expr {
|
||||
|
||||
@@ -51,6 +51,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::{
|
||||
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
|
||||
@@ -93,6 +94,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
struct LoweringContext<'a, 'hir> {
|
||||
tcx: TyCtxt<'hir>,
|
||||
resolver: &'a mut ResolverAstLowering,
|
||||
disambiguator: DisambiguatorState,
|
||||
|
||||
/// Used to allocate HIR nodes.
|
||||
arena: &'hir hir::Arena<'hir>,
|
||||
@@ -155,6 +157,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// Pseudo-globals.
|
||||
tcx,
|
||||
resolver,
|
||||
disambiguator: DisambiguatorState::new(),
|
||||
arena: tcx.hir_arena,
|
||||
|
||||
// HirId handling.
|
||||
@@ -546,6 +549,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
node_id: ast::NodeId,
|
||||
name: Option<Symbol>,
|
||||
def_kind: DefKind,
|
||||
def_path_data: DefPathData,
|
||||
span: Span,
|
||||
) -> LocalDefId {
|
||||
let parent = self.current_hir_id_owner.def_id;
|
||||
@@ -561,7 +565,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let def_id = self
|
||||
.tcx
|
||||
.at(span)
|
||||
.create_def(parent, name, def_kind, None, &mut self.resolver.disambiguator)
|
||||
.create_def(parent, name, def_kind, Some(def_path_data), &mut self.disambiguator)
|
||||
.def_id();
|
||||
|
||||
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
|
||||
@@ -846,6 +850,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
param,
|
||||
Some(kw::UnderscoreLifetime),
|
||||
DefKind::LifetimeParam,
|
||||
DefPathData::DesugaredAnonymousLifetime,
|
||||
ident.span,
|
||||
);
|
||||
debug!(?_def_id);
|
||||
@@ -2290,7 +2295,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// We're lowering a const argument that was originally thought to be a type argument,
|
||||
// so the def collector didn't create the def ahead of time. That's why we have to do
|
||||
// it here.
|
||||
let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
|
||||
let def_id = self.create_def(
|
||||
node_id,
|
||||
None,
|
||||
DefKind::AnonConst,
|
||||
DefPathData::LateAnonConst,
|
||||
span,
|
||||
);
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
|
||||
let path_expr = Expr {
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::sync::Arc;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_hir::{self as hir, LangItem, Target};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_span::source_map::{Spanned, respan};
|
||||
@@ -527,7 +528,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// We're generating a range end that didn't exist in the AST,
|
||||
// so the def collector didn't create the def ahead of time. That's why we have to do
|
||||
// it here.
|
||||
let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
|
||||
let def_id =
|
||||
self.create_def(node_id, None, DefKind::AnonConst, DefPathData::LateAnonConst, span);
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
|
||||
@@ -326,7 +326,8 @@ pub fn parse_cfg_attr(
|
||||
}) {
|
||||
Ok(r) => return Some(r),
|
||||
Err(e) => {
|
||||
let suggestions = CFG_ATTR_TEMPLATE.suggestions(cfg_attr.style, sym::cfg_attr);
|
||||
let suggestions =
|
||||
CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr);
|
||||
e.with_span_suggestions(
|
||||
cfg_attr.span,
|
||||
"must be of the form",
|
||||
@@ -356,7 +357,7 @@ pub fn parse_cfg_attr(
|
||||
template: CFG_ATTR_TEMPLATE,
|
||||
attribute: AttrPath::from_ast(&cfg_attr.get_normal_item().path),
|
||||
reason,
|
||||
attr_style: cfg_attr.style,
|
||||
suggestions: CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -388,6 +389,7 @@ fn parse_cfg_attr_internal<'a>(
|
||||
let cfg_predicate = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
attribute.span,
|
||||
attribute.get_normal_item().span(),
|
||||
attribute.style,
|
||||
AttrPath {
|
||||
segments: attribute
|
||||
|
||||
@@ -56,8 +56,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "inline");
|
||||
let suggestions = cx.suggestions();
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||
return None;
|
||||
|
||||
@@ -71,8 +71,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||
// Specifically `#[link = "dl"]` is accepted with a FCW
|
||||
// For more information, see https://github.com/rust-lang/rust/pull/143193
|
||||
ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => {
|
||||
let suggestions = <Self as CombineAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "link");
|
||||
let suggestions = cx.suggestions();
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||
return None;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use rustc_ast::AttrStyle;
|
||||
use rustc_errors::DiagArgValue;
|
||||
use rustc_hir::attrs::MacroUseArgs;
|
||||
|
||||
@@ -102,7 +101,7 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use);
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_err(IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
@@ -149,19 +148,14 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
|
||||
]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let suggestions = || {
|
||||
<Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(AttrStyle::Inner, "macro_export")
|
||||
};
|
||||
let local_inner_macros = match args {
|
||||
ArgParser::NoArgs => false,
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = list.single() else {
|
||||
let span = cx.attr_span;
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_lint(
|
||||
AttributeLintKind::InvalidMacroExportArguments {
|
||||
suggestions: suggestions(),
|
||||
},
|
||||
AttributeLintKind::InvalidMacroExportArguments { suggestions },
|
||||
span,
|
||||
);
|
||||
return None;
|
||||
@@ -170,10 +164,9 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
|
||||
Some(sym::local_inner_macros) => true,
|
||||
_ => {
|
||||
let span = cx.attr_span;
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_lint(
|
||||
AttributeLintKind::InvalidMacroExportArguments {
|
||||
suggestions: suggestions(),
|
||||
},
|
||||
AttributeLintKind::InvalidMacroExportArguments { suggestions },
|
||||
span,
|
||||
);
|
||||
return None;
|
||||
@@ -182,7 +175,7 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let span = cx.attr_span;
|
||||
let suggestions = suggestions();
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_err(IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
|
||||
@@ -45,8 +45,7 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
|
||||
Some(value_str)
|
||||
}
|
||||
ArgParser::List(_) => {
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "must_use");
|
||||
let suggestions = cx.suggestions();
|
||||
cx.emit_err(IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
|
||||
@@ -20,8 +20,7 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
||||
ArgParser::NoArgs => None,
|
||||
ArgParser::NameValue(name_value) => {
|
||||
let Some(str_value) = name_value.value_as_str() else {
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "ignore");
|
||||
let suggestions = cx.suggestions();
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(
|
||||
AttributeLintKind::IllFormedAttributeInput { suggestions },
|
||||
@@ -32,8 +31,7 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
||||
Some(str_value)
|
||||
}
|
||||
ArgParser::List(_) => {
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "ignore");
|
||||
let suggestions = cx.suggestions();
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||
return None;
|
||||
|
||||
@@ -337,8 +337,16 @@ pub struct Late;
|
||||
/// Gives [`AttributeParser`]s enough information to create errors, for example.
|
||||
pub struct AcceptContext<'f, 'sess, S: Stage> {
|
||||
pub(crate) shared: SharedContext<'f, 'sess, S>,
|
||||
/// The span of the attribute currently being parsed
|
||||
|
||||
/// The outer span of the attribute currently being parsed
|
||||
/// #[attribute(...)]
|
||||
/// ^^^^^^^^^^^^^^^^^ outer span
|
||||
/// For attributes in `cfg_attr`, the outer span and inner spans are equal.
|
||||
pub(crate) attr_span: Span,
|
||||
/// The inner span of the attribute currently being parsed
|
||||
/// #[attribute(...)]
|
||||
/// ^^^^^^^^^^^^^^ inner span
|
||||
pub(crate) inner_span: Span,
|
||||
|
||||
/// Whether it is an inner or outer attribute
|
||||
pub(crate) attr_style: AttrStyle,
|
||||
@@ -427,7 +435,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
|
||||
}),
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -438,7 +446,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -449,7 +457,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedList,
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -460,7 +468,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedNoArgs,
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -472,7 +480,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedIdentifier,
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -485,7 +493,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedNameValue(name),
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -497,7 +505,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::DuplicateKey(key),
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -510,7 +518,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::UnexpectedLiteral,
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -521,7 +529,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedSingleArgument,
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -532,7 +540,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -552,7 +560,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
strings: false,
|
||||
list: false,
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -573,7 +581,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
strings: false,
|
||||
list: true,
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -593,7 +601,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
strings: true,
|
||||
list: false,
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
suggestions: self.suggestions(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -605,6 +613,13 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn suggestions(&self) -> Vec<String> {
|
||||
// If the outer and inner spans are equal, we are parsing an attribute from `cfg_attr`,
|
||||
// So don't display an attribute style in the suggestions
|
||||
let style = (self.attr_span != self.inner_span).then_some(self.attr_style);
|
||||
self.template.suggestions(style, &self.attr_path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
|
||||
|
||||
@@ -142,6 +142,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
Self::parse_single_args(
|
||||
sess,
|
||||
attr.span,
|
||||
normal_attr.item.span(),
|
||||
attr.style,
|
||||
path.get_attribute_path(),
|
||||
target_span,
|
||||
@@ -159,6 +160,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
pub fn parse_single_args<T, I>(
|
||||
sess: &'sess Session,
|
||||
attr_span: Span,
|
||||
inner_span: Span,
|
||||
attr_style: AttrStyle,
|
||||
attr_path: AttrPath,
|
||||
target_span: Span,
|
||||
@@ -186,6 +188,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
},
|
||||
},
|
||||
attr_span,
|
||||
inner_span,
|
||||
attr_style,
|
||||
template,
|
||||
attr_path,
|
||||
@@ -305,6 +308,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span: lower_span(attr.span),
|
||||
inner_span: lower_span(attr.get_normal_item().span()),
|
||||
attr_style: attr.style,
|
||||
template: &accept.template,
|
||||
attr_path: path.get_attribute_path(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast::{self as ast, AttrStyle, Path};
|
||||
use rustc_ast::{self as ast, Path};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
|
||||
@@ -613,10 +613,10 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
||||
pub(crate) struct AttributeParseError<'a> {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) attr_span: Span,
|
||||
pub(crate) attr_style: AttrStyle,
|
||||
pub(crate) template: AttributeTemplate,
|
||||
pub(crate) attribute: AttrPath,
|
||||
pub(crate) reason: AttributeParseErrorReason<'a>,
|
||||
pub(crate) suggestions: Vec<String>,
|
||||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||
@@ -752,16 +752,15 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||
if let Some(link) = self.template.docs {
|
||||
diag.note(format!("for more information, visit <{link}>"));
|
||||
}
|
||||
let suggestions = self.template.suggestions(self.attr_style, &name);
|
||||
|
||||
diag.span_suggestions(
|
||||
self.attr_span,
|
||||
if suggestions.len() == 1 {
|
||||
if self.suggestions.len() == 1 {
|
||||
"must be of the form"
|
||||
} else {
|
||||
"try changing it to one of the following valid forms of the attribute"
|
||||
},
|
||||
suggestions,
|
||||
self.suggestions,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
annotate-snippets = "0.11"
|
||||
annotate-snippets = "0.12.7"
|
||||
anstream = "0.6.20"
|
||||
anstyle = "1.0.13"
|
||||
derive_setters = "0.1.6"
|
||||
|
||||
@@ -5,32 +5,70 @@
|
||||
//!
|
||||
//! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::error::Report;
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
use annotate_snippets::{Renderer, Snippet};
|
||||
use rustc_error_messages::FluentArgs;
|
||||
use rustc_span::SourceFile;
|
||||
use annotate_snippets::renderer::DEFAULT_TERM_WIDTH;
|
||||
use annotate_snippets::{AnnotationKind, Group, Origin, Padding, Patch, Renderer, Snippet};
|
||||
use anstream::ColorChoice;
|
||||
use derive_setters::Setters;
|
||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_error_messages::{FluentArgs, SpanLabel};
|
||||
use rustc_lint_defs::pluralize;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::emitter::FileWithAnnotatedLines;
|
||||
use crate::emitter::{
|
||||
ConfusionType, Destination, MAX_SUGGESTIONS, OutputTheme, detect_confusion_type, is_different,
|
||||
normalize_whitespace, should_show_source_code,
|
||||
};
|
||||
use crate::registry::Registry;
|
||||
use crate::snippet::Line;
|
||||
use crate::translation::{Translator, to_fluent_args};
|
||||
use crate::{
|
||||
CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, Level, MultiSpan, Style, Subdiag,
|
||||
SuggestionStyle, TerminalUrl,
|
||||
};
|
||||
|
||||
/// Generates diagnostics using annotate-snippet
|
||||
#[derive(Setters)]
|
||||
pub struct AnnotateSnippetEmitter {
|
||||
source_map: Option<Arc<SourceMap>>,
|
||||
#[setters(skip)]
|
||||
dst: IntoDynSyncSend<Destination>,
|
||||
sm: Option<Arc<SourceMap>>,
|
||||
#[setters(skip)]
|
||||
translator: Translator,
|
||||
|
||||
/// If true, hides the longer explanation text
|
||||
short_message: bool,
|
||||
/// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs.
|
||||
ui_testing: bool,
|
||||
ignored_directories_in_source_blocks: Vec<String>,
|
||||
diagnostic_width: Option<usize>,
|
||||
|
||||
macro_backtrace: bool,
|
||||
track_diagnostics: bool,
|
||||
terminal_url: TerminalUrl,
|
||||
theme: OutputTheme,
|
||||
}
|
||||
|
||||
impl Debug for AnnotateSnippetEmitter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("AnnotateSnippetEmitter")
|
||||
.field("short_message", &self.short_message)
|
||||
.field("ui_testing", &self.ui_testing)
|
||||
.field(
|
||||
"ignored_directories_in_source_blocks",
|
||||
&self.ignored_directories_in_source_blocks,
|
||||
)
|
||||
.field("diagnostic_width", &self.diagnostic_width)
|
||||
.field("macro_backtrace", &self.macro_backtrace)
|
||||
.field("track_diagnostics", &self.track_diagnostics)
|
||||
.field("terminal_url", &self.terminal_url)
|
||||
.field("theme", &self.theme)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Emitter for AnnotateSnippetEmitter {
|
||||
@@ -38,6 +76,10 @@ impl Emitter for AnnotateSnippetEmitter {
|
||||
fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
|
||||
let fluent_args = to_fluent_args(diag.args.iter());
|
||||
|
||||
if self.track_diagnostics && diag.span.has_primary_spans() && !diag.span.is_dummy() {
|
||||
diag.children.insert(0, diag.emitted_at_sub_diag());
|
||||
}
|
||||
|
||||
let mut suggestions = diag.suggestions.unwrap_tag();
|
||||
self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args);
|
||||
|
||||
@@ -55,12 +97,12 @@ impl Emitter for AnnotateSnippetEmitter {
|
||||
&diag.code,
|
||||
&diag.span,
|
||||
&diag.children,
|
||||
&suggestions,
|
||||
suggestions,
|
||||
);
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&SourceMap> {
|
||||
self.source_map.as_deref()
|
||||
self.sm.as_deref()
|
||||
}
|
||||
|
||||
fn should_show_explain(&self) -> bool {
|
||||
@@ -70,128 +112,648 @@ impl Emitter for AnnotateSnippetEmitter {
|
||||
fn translator(&self) -> &Translator {
|
||||
&self.translator
|
||||
}
|
||||
|
||||
fn supports_color(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides the source string for the given `line` of `file`
|
||||
fn source_string(file: Arc<SourceFile>, line: &Line) -> String {
|
||||
file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Maps [`crate::Level`] to [`annotate_snippets::Level`]
|
||||
fn annotation_level_for_level(level: Level) -> annotate_snippets::Level {
|
||||
fn annotation_level_for_level(level: Level) -> annotate_snippets::level::Level<'static> {
|
||||
match level {
|
||||
Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => {
|
||||
annotate_snippets::Level::Error
|
||||
Level::Bug | Level::DelayedBug => {
|
||||
annotate_snippets::Level::ERROR.with_name("error: internal compiler error")
|
||||
}
|
||||
Level::ForceWarning | Level::Warning => annotate_snippets::Level::Warning,
|
||||
Level::Note | Level::OnceNote => annotate_snippets::Level::Note,
|
||||
Level::Help | Level::OnceHelp => annotate_snippets::Level::Help,
|
||||
// FIXME(#59346): Not sure how to map this level
|
||||
Level::FailureNote => annotate_snippets::Level::Error,
|
||||
Level::Fatal | Level::Error => annotate_snippets::level::ERROR,
|
||||
Level::ForceWarning | Level::Warning => annotate_snippets::Level::WARNING,
|
||||
Level::Note | Level::OnceNote => annotate_snippets::Level::NOTE,
|
||||
Level::Help | Level::OnceHelp => annotate_snippets::Level::HELP,
|
||||
Level::FailureNote => annotate_snippets::Level::NOTE.no_name(),
|
||||
Level::Allow => panic!("Should not call with Allow"),
|
||||
Level::Expect => panic!("Should not call with Expect"),
|
||||
}
|
||||
}
|
||||
|
||||
impl AnnotateSnippetEmitter {
|
||||
pub fn new(
|
||||
source_map: Option<Arc<SourceMap>>,
|
||||
translator: Translator,
|
||||
short_message: bool,
|
||||
macro_backtrace: bool,
|
||||
) -> Self {
|
||||
Self { source_map, translator, short_message, ui_testing: false, macro_backtrace }
|
||||
pub fn new(dst: Destination, translator: Translator) -> Self {
|
||||
Self {
|
||||
dst: IntoDynSyncSend(dst),
|
||||
sm: None,
|
||||
translator,
|
||||
short_message: false,
|
||||
ui_testing: false,
|
||||
ignored_directories_in_source_blocks: Vec::new(),
|
||||
diagnostic_width: None,
|
||||
macro_backtrace: false,
|
||||
track_diagnostics: false,
|
||||
terminal_url: TerminalUrl::No,
|
||||
theme: OutputTheme::Ascii,
|
||||
}
|
||||
|
||||
/// Allows to modify `Self` to enable or disable the `ui_testing` flag.
|
||||
///
|
||||
/// If this is set to true, line numbers will be normalized as `LL` in the output.
|
||||
pub fn ui_testing(mut self, ui_testing: bool) -> Self {
|
||||
self.ui_testing = ui_testing;
|
||||
self
|
||||
}
|
||||
|
||||
fn emit_messages_default(
|
||||
&mut self,
|
||||
level: &Level,
|
||||
messages: &[(DiagMessage, Style)],
|
||||
msgs: &[(DiagMessage, Style)],
|
||||
args: &FluentArgs<'_>,
|
||||
code: &Option<ErrCode>,
|
||||
msp: &MultiSpan,
|
||||
_children: &[Subdiag],
|
||||
_suggestions: &[CodeSuggestion],
|
||||
children: &[Subdiag],
|
||||
suggestions: Vec<CodeSuggestion>,
|
||||
) {
|
||||
let message = self.translator.translate_messages(messages, args);
|
||||
if let Some(source_map) = &self.source_map {
|
||||
// Make sure our primary file comes first
|
||||
let primary_lo = if let Some(primary_span) = msp.primary_span().as_ref() {
|
||||
if primary_span.is_dummy() {
|
||||
// FIXME(#59346): Not sure when this is the case and what
|
||||
// should be done if it happens
|
||||
return;
|
||||
let renderer = self.renderer();
|
||||
let annotation_level = annotation_level_for_level(*level);
|
||||
|
||||
// If at least one portion of the message is styled, we need to
|
||||
// "pre-style" the message
|
||||
let mut title = if msgs.iter().any(|(_, style)| style != &crate::Style::NoStyle) {
|
||||
annotation_level
|
||||
.clone()
|
||||
.secondary_title(Cow::Owned(self.pre_style_msgs(msgs, *level, args)))
|
||||
} else {
|
||||
source_map.lookup_char_pos(primary_span.lo())
|
||||
annotation_level.clone().primary_title(self.translator.translate_messages(msgs, args))
|
||||
};
|
||||
|
||||
if let Some(c) = code {
|
||||
title = title.id(c.to_string());
|
||||
if let TerminalUrl::Yes = self.terminal_url {
|
||||
title = title.id_url(format!("https://doc.rust-lang.org/error_codes/{c}.html"));
|
||||
}
|
||||
}
|
||||
|
||||
let mut report = vec![];
|
||||
let mut group = Group::with_title(title);
|
||||
|
||||
// If we don't have span information, emit and exit
|
||||
let Some(sm) = self.sm.as_ref() else {
|
||||
group = group.elements(children.iter().map(|c| {
|
||||
let msg = self.translator.translate_messages(&c.messages, args).to_string();
|
||||
let level = annotation_level_for_level(c.level);
|
||||
level.message(msg)
|
||||
}));
|
||||
|
||||
report.push(group);
|
||||
if let Err(e) = emit_to_destination(
|
||||
renderer.render(&report),
|
||||
level,
|
||||
&mut self.dst,
|
||||
self.short_message,
|
||||
) {
|
||||
panic!("failed to emit error: {e}");
|
||||
}
|
||||
} else {
|
||||
// FIXME(#59346): Not sure when this is the case and what
|
||||
// should be done if it happens
|
||||
return;
|
||||
};
|
||||
let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp);
|
||||
if let Ok(pos) =
|
||||
annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name))
|
||||
{
|
||||
annotated_files.swap(0, pos);
|
||||
|
||||
let mut file_ann = collect_annotations(args, msp, sm, &self.translator);
|
||||
|
||||
// Make sure our primary file comes first
|
||||
let primary_span = msp.primary_span().unwrap_or_default();
|
||||
if !primary_span.is_dummy() {
|
||||
let primary_lo = sm.lookup_char_pos(primary_span.lo());
|
||||
if let Ok(pos) = file_ann.binary_search_by(|(f, _)| f.name.cmp(&primary_lo.file.name)) {
|
||||
file_ann.swap(0, pos);
|
||||
}
|
||||
// owned: file name, line source, line index, annotations
|
||||
type Owned = (String, String, usize, Vec<crate::snippet::Annotation>);
|
||||
let annotated_files: Vec<Owned> = annotated_files
|
||||
.into_iter()
|
||||
.flat_map(|annotated_file| {
|
||||
let file = annotated_file.file;
|
||||
annotated_file
|
||||
.lines
|
||||
.into_iter()
|
||||
.map(|line| {
|
||||
// Ensure the source file is present before we try
|
||||
// to load a string from it.
|
||||
// FIXME(#115869): support -Z ignore-directory-in-diagnostics-source-blocks
|
||||
source_map.ensure_source_file_source_present(&file);
|
||||
(
|
||||
format!("{}", source_map.filename_for_diagnostics(&file.name)),
|
||||
source_string(Arc::clone(&file), &line),
|
||||
line.line_index,
|
||||
line.annotations,
|
||||
|
||||
for (file_idx, (file, annotations)) in file_ann.into_iter().enumerate() {
|
||||
if should_show_source_code(&self.ignored_directories_in_source_blocks, sm, &file) {
|
||||
if let Some(snippet) = self.annotated_snippet(annotations, &file.name, sm) {
|
||||
group = group.element(snippet);
|
||||
}
|
||||
// we can't annotate anything if the source is unavailable.
|
||||
} else if !self.short_message {
|
||||
// We'll just print unannotated messages
|
||||
group = self.unannotated_messages(
|
||||
annotations,
|
||||
&file.name,
|
||||
sm,
|
||||
file_idx,
|
||||
&mut report,
|
||||
group,
|
||||
&annotation_level,
|
||||
);
|
||||
// If this is the last annotation for a file, and
|
||||
// this is the last file, and the first child is a
|
||||
// "secondary" message, we need to add padding
|
||||
// ╭▸ /rustc/FAKE_PREFIX/library/core/src/clone.rs:236:13
|
||||
// │
|
||||
// ├ note: the late bound lifetime parameter
|
||||
// │ (<- It adds *this*)
|
||||
// ╰ warning: this was previously accepted
|
||||
if let Some(c) = children.first()
|
||||
&& (!c.span.has_primary_spans() && !c.span.has_span_labels())
|
||||
{
|
||||
group = group.element(Padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for c in children {
|
||||
let level = annotation_level_for_level(c.level);
|
||||
|
||||
// If at least one portion of the message is styled, we need to
|
||||
// "pre-style" the message
|
||||
let msg = if c.messages.iter().any(|(_, style)| style != &crate::Style::NoStyle) {
|
||||
Cow::Owned(self.pre_style_msgs(&c.messages, c.level, args))
|
||||
} else {
|
||||
self.translator.translate_messages(&c.messages, args)
|
||||
};
|
||||
|
||||
// This is a secondary message with no span info
|
||||
if !c.span.has_primary_spans() && !c.span.has_span_labels() {
|
||||
group = group.element(level.clone().message(msg));
|
||||
continue;
|
||||
}
|
||||
|
||||
report.push(std::mem::replace(
|
||||
&mut group,
|
||||
Group::with_title(level.clone().secondary_title(msg)),
|
||||
));
|
||||
|
||||
let mut file_ann = collect_annotations(args, &c.span, sm, &self.translator);
|
||||
let primary_span = c.span.primary_span().unwrap_or_default();
|
||||
if !primary_span.is_dummy() {
|
||||
let primary_lo = sm.lookup_char_pos(primary_span.lo());
|
||||
if let Ok(pos) =
|
||||
file_ann.binary_search_by(|(f, _)| f.name.cmp(&primary_lo.file.name))
|
||||
{
|
||||
file_ann.swap(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
for (file_idx, (file, annotations)) in file_ann.into_iter().enumerate() {
|
||||
if should_show_source_code(&self.ignored_directories_in_source_blocks, sm, &file) {
|
||||
if let Some(snippet) = self.annotated_snippet(annotations, &file.name, sm) {
|
||||
group = group.element(snippet);
|
||||
}
|
||||
// we can't annotate anything if the source is unavailable.
|
||||
} else if !self.short_message {
|
||||
// We'll just print unannotated messages
|
||||
group = self.unannotated_messages(
|
||||
annotations,
|
||||
&file.name,
|
||||
sm,
|
||||
file_idx,
|
||||
&mut report,
|
||||
group,
|
||||
&level,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let suggestions_expected = suggestions
|
||||
.iter()
|
||||
.filter(|s| {
|
||||
matches!(
|
||||
s.style,
|
||||
SuggestionStyle::HideCodeInline
|
||||
| SuggestionStyle::ShowCode
|
||||
| SuggestionStyle::ShowAlways
|
||||
)
|
||||
})
|
||||
.collect::<Vec<Owned>>()
|
||||
})
|
||||
.collect();
|
||||
let code = code.map(|code| code.to_string());
|
||||
.count();
|
||||
for suggestion in suggestions {
|
||||
match suggestion.style {
|
||||
SuggestionStyle::CompletelyHidden => {
|
||||
// do not display this suggestion, it is meant only for tools
|
||||
}
|
||||
SuggestionStyle::HideCodeAlways => {
|
||||
let msg = self
|
||||
.translator
|
||||
.translate_messages(&[(suggestion.msg.to_owned(), Style::HeaderMsg)], args);
|
||||
group = group.element(annotate_snippets::Level::HELP.message(msg));
|
||||
}
|
||||
SuggestionStyle::HideCodeInline
|
||||
| SuggestionStyle::ShowCode
|
||||
| SuggestionStyle::ShowAlways => {
|
||||
let substitutions = suggestion
|
||||
.substitutions
|
||||
.into_iter()
|
||||
.filter_map(|mut subst| {
|
||||
// Suggestions coming from macros can have malformed spans. This is a heavy
|
||||
// handed approach to avoid ICEs by ignoring the suggestion outright.
|
||||
let invalid =
|
||||
subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
|
||||
if invalid {
|
||||
debug!("suggestion contains an invalid span: {:?}", subst);
|
||||
}
|
||||
|
||||
let snippets =
|
||||
annotated_files.iter().map(|(file_name, source, line_index, annotations)| {
|
||||
// Assumption: all spans are in the same file, and all spans
|
||||
// are disjoint. Sort in ascending order.
|
||||
subst.parts.sort_by_key(|part| part.span.lo());
|
||||
// Verify the assumption that all spans are disjoint
|
||||
assert_eq!(
|
||||
subst.parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
|
||||
None,
|
||||
"all spans must be disjoint",
|
||||
);
|
||||
|
||||
// Account for cases where we are suggesting the same code that's already
|
||||
// there. This shouldn't happen often, but in some cases for multipart
|
||||
// suggestions it's much easier to handle it here than in the origin.
|
||||
subst.parts.retain(|p| is_different(sm, &p.snippet, p.span));
|
||||
|
||||
let item_span = subst.parts.first()?;
|
||||
let file = sm.lookup_source_file(item_span.span.lo());
|
||||
if !invalid
|
||||
&& should_show_source_code(
|
||||
&self.ignored_directories_in_source_blocks,
|
||||
sm,
|
||||
&file,
|
||||
)
|
||||
{
|
||||
Some(subst)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if substitutions.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut msg = self
|
||||
.translator
|
||||
.translate_message(&suggestion.msg, args)
|
||||
.map_err(Report::new)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let lo = substitutions
|
||||
.iter()
|
||||
.find_map(|sub| sub.parts.first().map(|p| p.span.lo()))
|
||||
.unwrap();
|
||||
let file = sm.lookup_source_file(lo);
|
||||
|
||||
let filename =
|
||||
sm.filename_for_diagnostics(&file.name).to_string_lossy().to_string();
|
||||
|
||||
let other_suggestions = substitutions.len().saturating_sub(MAX_SUGGESTIONS);
|
||||
|
||||
let subs = substitutions
|
||||
.into_iter()
|
||||
.take(MAX_SUGGESTIONS)
|
||||
.filter_map(|sub| {
|
||||
let mut confusion_type = ConfusionType::None;
|
||||
for part in &sub.parts {
|
||||
let part_confusion =
|
||||
detect_confusion_type(sm, &part.snippet, part.span);
|
||||
confusion_type = confusion_type.combine(part_confusion);
|
||||
}
|
||||
|
||||
if !matches!(confusion_type, ConfusionType::None) {
|
||||
msg.push_str(confusion_type.label_text());
|
||||
}
|
||||
|
||||
let mut parts = sub
|
||||
.parts
|
||||
.into_iter()
|
||||
.filter_map(|p| {
|
||||
if is_different(sm, &p.snippet, p.span) {
|
||||
Some((p.span, p.snippet))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if parts.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let spans = parts.iter().map(|(span, _)| *span).collect::<Vec<_>>();
|
||||
// The suggestion adds an entire line of code, ending on a newline, so we'll also
|
||||
// print the *following* line, to provide context of what we're advising people to
|
||||
// do. Otherwise you would only see contextless code that can be confused for
|
||||
// already existing code, despite the colors and UI elements.
|
||||
// We special case `#[derive(_)]\n` and other attribute suggestions, because those
|
||||
// are the ones where context is most useful.
|
||||
let fold = if let [(p, snippet)] = &mut parts[..]
|
||||
&& snippet.trim().starts_with("#[")
|
||||
// This allows for spaces to come between the attribute and the newline
|
||||
&& snippet.trim().ends_with("]")
|
||||
&& snippet.ends_with('\n')
|
||||
&& p.hi() == p.lo()
|
||||
&& let Ok(b) = sm.span_to_prev_source(*p)
|
||||
&& let b = b.rsplit_once('\n').unwrap_or_else(|| ("", &b)).1
|
||||
&& b.trim().is_empty()
|
||||
{
|
||||
// FIXME: This is a hack:
|
||||
// The span for attribute suggestions often times points to the
|
||||
// beginning of an item, disregarding leading whitespace. This
|
||||
// causes the attribute to be properly indented, but leaves original
|
||||
// item without indentation when rendered.
|
||||
// This fixes that problem by adjusting the span to point to the start
|
||||
// of the whitespace, and adds the whitespace to the replacement.
|
||||
//
|
||||
// Source: " extern "custom" fn negate(a: i64) -> i64 {\n"
|
||||
// Span: 4..4
|
||||
// Replacement: "#[unsafe(naked)]\n"
|
||||
//
|
||||
// Before:
|
||||
// help: convert this to an `#[unsafe(naked)]` function
|
||||
// |
|
||||
// LL + #[unsafe(naked)]
|
||||
// LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
// |
|
||||
//
|
||||
// After
|
||||
// help: convert this to an `#[unsafe(naked)]` function
|
||||
// |
|
||||
// LL + #[unsafe(naked)]
|
||||
// LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
// |
|
||||
if !b.is_empty() && !snippet.ends_with(b) {
|
||||
snippet.insert_str(0, b);
|
||||
let offset = BytePos(b.len() as u32);
|
||||
*p = p.with_lo(p.lo() - offset).shrink_to_lo();
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if let Some((bounding_span, source, line_offset)) =
|
||||
shrink_file(spans.as_slice(), &file.name, sm)
|
||||
{
|
||||
let adj_lo = bounding_span.lo().to_usize();
|
||||
Some(
|
||||
Snippet::source(source)
|
||||
.line_start(*line_index)
|
||||
.origin(file_name)
|
||||
// FIXME(#59346): Not really sure when `fold` should be true or false
|
||||
.fold(false)
|
||||
.annotations(annotations.iter().map(|annotation| {
|
||||
annotation_level_for_level(*level)
|
||||
.span(annotation.start_col.display..annotation.end_col.display)
|
||||
.label(annotation.label.as_deref().unwrap_or_default())
|
||||
}))
|
||||
.line_start(line_offset)
|
||||
.path(filename.clone())
|
||||
.fold(fold)
|
||||
.patches(parts.into_iter().map(
|
||||
|(span, replacement)| {
|
||||
let lo =
|
||||
span.lo().to_usize().saturating_sub(adj_lo);
|
||||
let hi =
|
||||
span.hi().to_usize().saturating_sub(adj_lo);
|
||||
|
||||
Patch::new(lo..hi, replacement)
|
||||
},
|
||||
)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !subs.is_empty() {
|
||||
report.push(std::mem::replace(
|
||||
&mut group,
|
||||
Group::with_title(annotate_snippets::Level::HELP.secondary_title(msg)),
|
||||
));
|
||||
|
||||
group = group.elements(subs);
|
||||
if other_suggestions > 0 {
|
||||
group = group.element(
|
||||
annotate_snippets::Level::NOTE.no_name().message(format!(
|
||||
"and {} other candidate{}",
|
||||
other_suggestions,
|
||||
pluralize!(other_suggestions)
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This hack should be removed once annotate_snippets is the
|
||||
// default emitter.
|
||||
if suggestions_expected > 0 && report.is_empty() {
|
||||
group = group.element(Padding);
|
||||
}
|
||||
|
||||
if !group.is_empty() {
|
||||
report.push(group);
|
||||
}
|
||||
if let Err(e) =
|
||||
emit_to_destination(renderer.render(&report), level, &mut self.dst, self.short_message)
|
||||
{
|
||||
panic!("failed to emit error: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
fn renderer(&self) -> Renderer {
|
||||
let width = if let Some(width) = self.diagnostic_width {
|
||||
width
|
||||
} else if self.ui_testing || cfg!(miri) {
|
||||
DEFAULT_TERM_WIDTH
|
||||
} else {
|
||||
termize::dimensions().map(|(w, _)| w).unwrap_or(DEFAULT_TERM_WIDTH)
|
||||
};
|
||||
let decor_style = match self.theme {
|
||||
OutputTheme::Ascii => annotate_snippets::renderer::DecorStyle::Ascii,
|
||||
OutputTheme::Unicode => annotate_snippets::renderer::DecorStyle::Unicode,
|
||||
};
|
||||
|
||||
match self.dst.current_choice() {
|
||||
ColorChoice::AlwaysAnsi | ColorChoice::Always | ColorChoice::Auto => Renderer::styled(),
|
||||
ColorChoice::Never => Renderer::plain(),
|
||||
}
|
||||
.term_width(width)
|
||||
.anonymized_line_numbers(self.ui_testing)
|
||||
.decor_style(decor_style)
|
||||
.short_message(self.short_message)
|
||||
}
|
||||
|
||||
fn pre_style_msgs(
|
||||
&self,
|
||||
msgs: &[(DiagMessage, Style)],
|
||||
level: Level,
|
||||
args: &FluentArgs<'_>,
|
||||
) -> String {
|
||||
msgs.iter()
|
||||
.filter_map(|(m, style)| {
|
||||
let text = self.translator.translate_message(m, args).map_err(Report::new).unwrap();
|
||||
let style = style.anstyle(level);
|
||||
if text.is_empty() { None } else { Some(format!("{style}{text}{style:#}")) }
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn annotated_snippet<'a>(
|
||||
&self,
|
||||
annotations: Vec<Annotation>,
|
||||
file_name: &FileName,
|
||||
sm: &Arc<SourceMap>,
|
||||
) -> Option<Snippet<'a, annotate_snippets::Annotation<'a>>> {
|
||||
let spans = annotations.iter().map(|a| a.span).collect::<Vec<_>>();
|
||||
if let Some((bounding_span, source, offset_line)) = shrink_file(&spans, file_name, sm) {
|
||||
let adj_lo = bounding_span.lo().to_usize();
|
||||
let filename = sm.filename_for_diagnostics(file_name).to_string_lossy().to_string();
|
||||
Some(Snippet::source(source).line_start(offset_line).path(filename).annotations(
|
||||
annotations.into_iter().map(move |a| {
|
||||
let lo = a.span.lo().to_usize().saturating_sub(adj_lo);
|
||||
let hi = a.span.hi().to_usize().saturating_sub(adj_lo);
|
||||
let ann = a.kind.span(lo..hi);
|
||||
if let Some(label) = a.label { ann.label(label) } else { ann }
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn unannotated_messages<'a>(
|
||||
&self,
|
||||
annotations: Vec<Annotation>,
|
||||
file_name: &FileName,
|
||||
sm: &Arc<SourceMap>,
|
||||
file_idx: usize,
|
||||
report: &mut Vec<Group<'a>>,
|
||||
mut group: Group<'a>,
|
||||
level: &annotate_snippets::level::Level<'static>,
|
||||
) -> Group<'a> {
|
||||
let filename = sm.filename_for_diagnostics(file_name).to_string_lossy().to_string();
|
||||
let mut line_tracker = vec![];
|
||||
for (i, a) in annotations.into_iter().enumerate() {
|
||||
let lo = sm.lookup_char_pos(a.span.lo());
|
||||
let hi = sm.lookup_char_pos(a.span.hi());
|
||||
if i == 0 || (a.label.is_some()) {
|
||||
// Render each new file after the first in its own Group
|
||||
// ╭▸ $DIR/deriving-meta-unknown-trait.rs:1:10
|
||||
// │
|
||||
// LL │ #[derive(Eqr)]
|
||||
// │ ━━━
|
||||
// ╰╴ (<- It makes it so *this* will get printed)
|
||||
// ╭▸ $SRC_DIR/core/src/option.rs:594:0
|
||||
// ⸬ $SRC_DIR/core/src/option.rs:602:4
|
||||
// │
|
||||
// ╰ note: not covered
|
||||
if i == 0 && file_idx != 0 {
|
||||
report.push(std::mem::replace(&mut group, Group::with_level(level.clone())));
|
||||
}
|
||||
|
||||
if !line_tracker.contains(&lo.line) {
|
||||
line_tracker.push(lo.line);
|
||||
// ╭▸ $SRC_DIR/core/src/option.rs:594:0 (<- It adds *this*)
|
||||
// ⸬ $SRC_DIR/core/src/option.rs:602:4
|
||||
// │
|
||||
// ╰ note: not covered
|
||||
group = group.element(
|
||||
Origin::path(filename.clone())
|
||||
.line(sm.doctest_offset_line(file_name, lo.line))
|
||||
.char_column(lo.col_display),
|
||||
);
|
||||
}
|
||||
|
||||
if hi.line > lo.line
|
||||
&& a.label.as_ref().is_some_and(|l| !l.is_empty())
|
||||
&& !line_tracker.contains(&hi.line)
|
||||
{
|
||||
line_tracker.push(hi.line);
|
||||
// ╭▸ $SRC_DIR/core/src/option.rs:594:0
|
||||
// ⸬ $SRC_DIR/core/src/option.rs:602:4 (<- It adds *this*)
|
||||
// │
|
||||
// ╰ note: not covered
|
||||
group = group.element(
|
||||
Origin::path(filename.clone())
|
||||
.line(sm.doctest_offset_line(file_name, hi.line))
|
||||
.char_column(hi.col_display),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(label) = a.label
|
||||
&& !label.is_empty()
|
||||
{
|
||||
// ╭▸ $SRC_DIR/core/src/option.rs:594:0
|
||||
// ⸬ $SRC_DIR/core/src/option.rs:602:4
|
||||
// │ (<- It adds *this*)
|
||||
// ╰ note: not covered (<- and *this*)
|
||||
group = group
|
||||
.element(Padding)
|
||||
.element(annotate_snippets::Level::NOTE.message(label));
|
||||
}
|
||||
}
|
||||
}
|
||||
group
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_to_destination(
|
||||
rendered: String,
|
||||
lvl: &Level,
|
||||
dst: &mut Destination,
|
||||
short_message: bool,
|
||||
) -> io::Result<()> {
|
||||
use crate::lock;
|
||||
let _buffer_lock = lock::acquire_global_lock("rustc_errors");
|
||||
writeln!(dst, "{rendered}")?;
|
||||
if !short_message && !lvl.is_failure_note() {
|
||||
writeln!(dst)?;
|
||||
}
|
||||
dst.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Annotation {
|
||||
kind: AnnotationKind,
|
||||
span: Span,
|
||||
label: Option<String>,
|
||||
}
|
||||
|
||||
fn collect_annotations(
|
||||
args: &FluentArgs<'_>,
|
||||
msp: &MultiSpan,
|
||||
sm: &Arc<SourceMap>,
|
||||
translator: &Translator,
|
||||
) -> Vec<(Arc<SourceFile>, Vec<Annotation>)> {
|
||||
let mut output: Vec<(Arc<SourceFile>, Vec<Annotation>)> = vec![];
|
||||
|
||||
for SpanLabel { span, is_primary, label } in msp.span_labels() {
|
||||
// If we don't have a useful span, pick the primary span if that exists.
|
||||
// Worst case we'll just print an error at the top of the main file.
|
||||
let span = match (span.is_dummy(), msp.primary_span()) {
|
||||
(_, None) | (false, _) => span,
|
||||
(true, Some(span)) => span,
|
||||
};
|
||||
let file = sm.lookup_source_file(span.lo());
|
||||
|
||||
let kind = if is_primary { AnnotationKind::Primary } else { AnnotationKind::Context };
|
||||
|
||||
let label = label.as_ref().map(|m| {
|
||||
normalize_whitespace(
|
||||
&translator.translate_message(m, args).map_err(Report::new).unwrap(),
|
||||
)
|
||||
});
|
||||
let mut message = annotation_level_for_level(*level).title(&message).snippets(snippets);
|
||||
if let Some(code) = code.as_deref() {
|
||||
message = message.id(code)
|
||||
}
|
||||
// FIXME(#59346): Figure out if we can _always_ print to stderr or not.
|
||||
// `emitter.rs` has the `Destination` enum that lists various possible output
|
||||
// destinations.
|
||||
let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing);
|
||||
eprintln!("{}", renderer.render(message))
|
||||
}
|
||||
// FIXME(#59346): Is it ok to return None if there's no source_map?
|
||||
|
||||
let ann = Annotation { kind, span, label };
|
||||
if sm.is_valid_span(ann.span).is_ok() {
|
||||
// Look through each of our files for the one we're adding to. We
|
||||
// use each files `stable_id` to avoid issues with file name
|
||||
// collisions when multiple versions of the same crate are present
|
||||
// in the dependency graph
|
||||
if let Some((_, annotations)) =
|
||||
output.iter_mut().find(|(f, _)| f.stable_id == file.stable_id)
|
||||
{
|
||||
annotations.push(ann);
|
||||
} else {
|
||||
output.push((file, vec![ann]));
|
||||
}
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
fn shrink_file(
|
||||
spans: &[Span],
|
||||
file_name: &FileName,
|
||||
sm: &Arc<SourceMap>,
|
||||
) -> Option<(Span, String, usize)> {
|
||||
let lo_byte = spans.iter().map(|s| s.lo()).min()?;
|
||||
let lo_loc = sm.lookup_char_pos(lo_byte);
|
||||
let lo = lo_loc.file.line_bounds(lo_loc.line.saturating_sub(1)).start;
|
||||
|
||||
let hi_byte = spans.iter().map(|s| s.hi()).max()?;
|
||||
let hi_loc = sm.lookup_char_pos(hi_byte);
|
||||
let hi = lo_loc.file.line_bounds(hi_loc.line.saturating_sub(1)).end;
|
||||
|
||||
let bounding_span = Span::with_root_ctxt(lo, hi);
|
||||
let source = sm.span_to_snippet(bounding_span).unwrap_or_default();
|
||||
let offset_line = sm.doctest_offset_line(file_name, lo_loc.line);
|
||||
|
||||
Some((bounding_span, source, offset_line))
|
||||
}
|
||||
|
||||
@@ -133,24 +133,29 @@ pub struct AttributeTemplate {
|
||||
}
|
||||
|
||||
impl AttributeTemplate {
|
||||
pub fn suggestions(&self, style: AttrStyle, name: impl std::fmt::Display) -> Vec<String> {
|
||||
pub fn suggestions(
|
||||
&self,
|
||||
style: Option<AttrStyle>,
|
||||
name: impl std::fmt::Display,
|
||||
) -> Vec<String> {
|
||||
let mut suggestions = vec![];
|
||||
let inner = match style {
|
||||
AttrStyle::Outer => "",
|
||||
AttrStyle::Inner => "!",
|
||||
let (start, end) = match style {
|
||||
Some(AttrStyle::Outer) => ("#[", "]"),
|
||||
Some(AttrStyle::Inner) => ("#![", "]"),
|
||||
None => ("", ""),
|
||||
};
|
||||
if self.word {
|
||||
suggestions.push(format!("#{inner}[{name}]"));
|
||||
suggestions.push(format!("{start}{name}{end}"));
|
||||
}
|
||||
if let Some(descr) = self.list {
|
||||
for descr in descr {
|
||||
suggestions.push(format!("#{inner}[{name}({descr})]"));
|
||||
suggestions.push(format!("{start}{name}({descr}){end}"));
|
||||
}
|
||||
}
|
||||
suggestions.extend(self.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
|
||||
suggestions.extend(self.one_of.iter().map(|&word| format!("{start}{name}({word}){end}")));
|
||||
if let Some(descr) = self.name_value_str {
|
||||
for descr in descr {
|
||||
suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
|
||||
suggestions.push(format!("{start}{name} = \"{descr}\"{end}"));
|
||||
}
|
||||
}
|
||||
suggestions.sort();
|
||||
|
||||
@@ -302,6 +302,10 @@ pub enum DefPathData {
|
||||
Ctor,
|
||||
/// A constant expression (see `{ast,hir}::AnonConst`).
|
||||
AnonConst,
|
||||
/// A constant expression created during AST->HIR lowering..
|
||||
LateAnonConst,
|
||||
/// A fresh anonymous lifetime created by desugaring elided lifetimes.
|
||||
DesugaredAnonymousLifetime,
|
||||
/// An existential `impl Trait` type node.
|
||||
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
|
||||
OpaqueTy,
|
||||
@@ -454,6 +458,8 @@ impl DefPathData {
|
||||
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name)
|
||||
| OpaqueLifetime(name) => Some(name),
|
||||
|
||||
DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime),
|
||||
|
||||
Impl
|
||||
| ForeignMod
|
||||
| CrateRoot
|
||||
@@ -462,6 +468,7 @@ impl DefPathData {
|
||||
| Closure
|
||||
| Ctor
|
||||
| AnonConst
|
||||
| LateAnonConst
|
||||
| OpaqueTy
|
||||
| AnonAssocTy(..)
|
||||
| SyntheticCoroutineBody
|
||||
@@ -475,6 +482,8 @@ impl DefPathData {
|
||||
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name)
|
||||
| OpaqueLifetime(name) => Some(name),
|
||||
|
||||
DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime),
|
||||
|
||||
Impl
|
||||
| ForeignMod
|
||||
| CrateRoot
|
||||
@@ -483,6 +492,7 @@ impl DefPathData {
|
||||
| Closure
|
||||
| Ctor
|
||||
| AnonConst
|
||||
| LateAnonConst
|
||||
| OpaqueTy
|
||||
| SyntheticCoroutineBody
|
||||
| NestedStatic => None,
|
||||
@@ -502,7 +512,8 @@ impl DefPathData {
|
||||
GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm },
|
||||
Closure => DefPathDataName::Anon { namespace: sym::closure },
|
||||
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
|
||||
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
|
||||
AnonConst | LateAnonConst => DefPathDataName::Anon { namespace: sym::constant },
|
||||
DesugaredAnonymousLifetime => DefPathDataName::Named(kw::UnderscoreLifetime),
|
||||
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
|
||||
AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc },
|
||||
SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic },
|
||||
|
||||
@@ -37,7 +37,6 @@ use rustc_errors::{Diag, ErrorGuaranteed, LintBuffer};
|
||||
use rustc_hir::attrs::{AttributeKind, StrippedCfgItem};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
||||
use rustc_hir::definitions::DisambiguatorState;
|
||||
use rustc_hir::{LangItem, attrs as attr, find_attr};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::BitMatrix;
|
||||
@@ -211,8 +210,6 @@ pub struct ResolverAstLowering {
|
||||
|
||||
pub node_id_to_def_id: NodeMap<LocalDefId>,
|
||||
|
||||
pub disambiguator: DisambiguatorState,
|
||||
|
||||
pub trait_map: NodeMap<Vec<hir::TraitCandidate>>,
|
||||
/// List functions and methods for which lifetime elision was successful.
|
||||
pub lifetime_elision_allowed: FxHashSet<ast::NodeId>,
|
||||
|
||||
@@ -2156,6 +2156,7 @@ fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
|
||||
|
||||
DefPathData::ValueNs(..)
|
||||
| DefPathData::AnonConst
|
||||
| DefPathData::LateAnonConst
|
||||
| DefPathData::Closure
|
||||
| DefPathData::Ctor => Namespace::ValueNS,
|
||||
|
||||
|
||||
@@ -1791,7 +1791,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||
.into_items()
|
||||
.map(|(k, f)| (k, f.key()))
|
||||
.collect(),
|
||||
disambiguator: self.disambiguator,
|
||||
trait_map: self.trait_map,
|
||||
lifetime_elision_allowed: self.lifetime_elision_allowed,
|
||||
lint_buffer: Steal::new(self.lint_buffer),
|
||||
|
||||
@@ -712,7 +712,8 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||
hir::definitions::DefPathData::ValueNs(..) => "v",
|
||||
hir::definitions::DefPathData::Closure => "C",
|
||||
hir::definitions::DefPathData::Ctor => "c",
|
||||
hir::definitions::DefPathData::AnonConst => "k",
|
||||
hir::definitions::DefPathData::AnonConst => "K",
|
||||
hir::definitions::DefPathData::LateAnonConst => "k",
|
||||
hir::definitions::DefPathData::OpaqueTy => "i",
|
||||
hir::definitions::DefPathData::SyntheticCoroutineBody => "s",
|
||||
hir::definitions::DefPathData::NestedStatic => "n",
|
||||
@@ -722,6 +723,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||
| hir::definitions::DefPathData::MacroNs(..)
|
||||
| hir::definitions::DefPathData::OpaqueLifetime(..)
|
||||
| hir::definitions::DefPathData::LifetimeNs(..)
|
||||
| hir::definitions::DefPathData::DesugaredAnonymousLifetime
|
||||
| hir::definitions::DefPathData::AnonAssocTy(..) => {
|
||||
bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
|
||||
}
|
||||
|
||||
@@ -955,7 +955,24 @@ fn default_emitter(
|
||||
|
||||
if let HumanReadableErrorType::AnnotateSnippet = kind {
|
||||
let emitter =
|
||||
AnnotateSnippetEmitter::new(source_map, translator, short, macro_backtrace);
|
||||
AnnotateSnippetEmitter::new(stderr_destination(color_config), translator)
|
||||
.sm(source_map)
|
||||
.short_message(short)
|
||||
.diagnostic_width(sopts.diagnostic_width)
|
||||
.macro_backtrace(macro_backtrace)
|
||||
.track_diagnostics(track_diagnostics)
|
||||
.terminal_url(terminal_url)
|
||||
.theme(if let HumanReadableErrorType::Unicode = kind {
|
||||
OutputTheme::Unicode
|
||||
} else {
|
||||
OutputTheme::Ascii
|
||||
})
|
||||
.ignored_directories_in_source_blocks(
|
||||
sopts
|
||||
.unstable_opts
|
||||
.ignore_directory_in_diagnostics_source_blocks
|
||||
.clone(),
|
||||
);
|
||||
Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
|
||||
} else {
|
||||
let emitter = HumanEmitter::new(stderr_destination(color_config), translator)
|
||||
|
||||
@@ -877,7 +877,8 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
|
||||
DefPathData::ValueNs(_) => 'v',
|
||||
DefPathData::Closure => 'C',
|
||||
DefPathData::Ctor => 'c',
|
||||
DefPathData::AnonConst => 'k',
|
||||
DefPathData::AnonConst => 'K',
|
||||
DefPathData::LateAnonConst => 'k',
|
||||
DefPathData::OpaqueTy => 'i',
|
||||
DefPathData::SyntheticCoroutineBody => 's',
|
||||
DefPathData::NestedStatic => 'n',
|
||||
@@ -889,6 +890,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
|
||||
| DefPathData::Impl
|
||||
| DefPathData::MacroNs(_)
|
||||
| DefPathData::LifetimeNs(_)
|
||||
| DefPathData::DesugaredAnonymousLifetime
|
||||
| DefPathData::OpaqueLifetime(_)
|
||||
| DefPathData::AnonAssocTy(..) => {
|
||||
bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::directives::line::{DirectiveLine, line_directive};
|
||||
use crate::directives::needs::CachedNeedsConditions;
|
||||
use crate::edition::{Edition, parse_edition};
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
use crate::executor::{CollectedTestDesc, ShouldFail};
|
||||
use crate::util::static_regex;
|
||||
use crate::{fatal, help};
|
||||
|
||||
@@ -1366,10 +1366,10 @@ pub(crate) fn make_test_description(
|
||||
// The `should-fail` annotation doesn't apply to pretty tests,
|
||||
// since we run the pretty printer across all tests by default.
|
||||
// If desired, we could add a `should-fail-pretty` annotation.
|
||||
let should_panic = match config.mode {
|
||||
TestMode::Pretty => ShouldPanic::No,
|
||||
_ if should_fail => ShouldPanic::Yes,
|
||||
_ => ShouldPanic::No,
|
||||
let should_fail = if should_fail && config.mode != TestMode::Pretty {
|
||||
ShouldFail::Yes
|
||||
} else {
|
||||
ShouldFail::No
|
||||
};
|
||||
|
||||
CollectedTestDesc {
|
||||
@@ -1377,7 +1377,7 @@ pub(crate) fn make_test_description(
|
||||
filterable_path: filterable_path.to_owned(),
|
||||
ignore,
|
||||
ignore_message,
|
||||
should_panic,
|
||||
should_fail,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::directives::{
|
||||
extract_llvm_version, extract_version_range, iter_directives, line_directive, parse_edition,
|
||||
parse_normalize_rule,
|
||||
};
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
use crate::executor::{CollectedTestDesc, ShouldFail};
|
||||
|
||||
fn make_test_description(
|
||||
config: &Config,
|
||||
@@ -247,9 +247,9 @@ fn should_fail() {
|
||||
let p = Utf8Path::new("a.rs");
|
||||
|
||||
let d = make_test_description(&config, tn.clone(), p, p, "", None);
|
||||
assert_eq!(d.should_panic, ShouldPanic::No);
|
||||
assert_eq!(d.should_fail, ShouldFail::No);
|
||||
let d = make_test_description(&config, tn, p, p, "//@ should-fail", None);
|
||||
assert_eq!(d.should_panic, ShouldPanic::Yes);
|
||||
assert_eq!(d.should_fail, ShouldFail::Yes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -98,32 +98,43 @@ pub(crate) fn run_tests(config: &Config, tests: Vec<CollectedTest>) -> bool {
|
||||
fn spawn_test_thread(
|
||||
id: TestId,
|
||||
test: &CollectedTest,
|
||||
completion_tx: mpsc::Sender<TestCompletion>,
|
||||
completion_sender: mpsc::Sender<TestCompletion>,
|
||||
) -> Option<thread::JoinHandle<()>> {
|
||||
if test.desc.ignore && !test.config.run_ignored {
|
||||
completion_tx
|
||||
completion_sender
|
||||
.send(TestCompletion { id, outcome: TestOutcome::Ignored, stdout: None })
|
||||
.unwrap();
|
||||
return None;
|
||||
}
|
||||
|
||||
let runnable_test = RunnableTest::new(test);
|
||||
let should_panic = test.desc.should_panic;
|
||||
let run_test = move || run_test_inner(id, should_panic, runnable_test, completion_tx);
|
||||
|
||||
let args = TestThreadArgs {
|
||||
id,
|
||||
config: Arc::clone(&test.config),
|
||||
testpaths: test.testpaths.clone(),
|
||||
revision: test.revision.clone(),
|
||||
should_fail: test.desc.should_fail,
|
||||
completion_sender,
|
||||
};
|
||||
let thread_builder = thread::Builder::new().name(test.desc.name.clone());
|
||||
let join_handle = thread_builder.spawn(run_test).unwrap();
|
||||
let join_handle = thread_builder.spawn(move || test_thread_main(args)).unwrap();
|
||||
Some(join_handle)
|
||||
}
|
||||
|
||||
/// Runs a single test, within the dedicated thread spawned by the caller.
|
||||
fn run_test_inner(
|
||||
/// All of the owned data needed by `test_thread_main`.
|
||||
struct TestThreadArgs {
|
||||
id: TestId,
|
||||
should_panic: ShouldPanic,
|
||||
runnable_test: RunnableTest,
|
||||
|
||||
config: Arc<Config>,
|
||||
testpaths: TestPaths,
|
||||
revision: Option<String>,
|
||||
should_fail: ShouldFail,
|
||||
|
||||
completion_sender: mpsc::Sender<TestCompletion>,
|
||||
) {
|
||||
let capture = CaptureKind::for_config(&runnable_test.config);
|
||||
}
|
||||
|
||||
/// Runs a single test, within the dedicated thread spawned by the caller.
|
||||
fn test_thread_main(args: TestThreadArgs) {
|
||||
let capture = CaptureKind::for_config(&args.config);
|
||||
|
||||
// Install a panic-capture buffer for use by the custom panic hook.
|
||||
if capture.should_set_panic_hook() {
|
||||
@@ -133,7 +144,24 @@ fn run_test_inner(
|
||||
let stdout = capture.stdout();
|
||||
let stderr = capture.stderr();
|
||||
|
||||
let panic_payload = panic::catch_unwind(move || runnable_test.run(stdout, stderr)).err();
|
||||
// Run the test, catching any panics so that we can gracefully report
|
||||
// failure (or success).
|
||||
//
|
||||
// FIXME(Zalathar): Ideally we would report test failures with `Result`,
|
||||
// and use panics only for bugs within compiletest itself, but that would
|
||||
// require a major overhaul of error handling in the test runners.
|
||||
let panic_payload = panic::catch_unwind(|| {
|
||||
__rust_begin_short_backtrace(|| {
|
||||
crate::runtest::run(
|
||||
&args.config,
|
||||
stdout,
|
||||
stderr,
|
||||
&args.testpaths,
|
||||
args.revision.as_deref(),
|
||||
);
|
||||
});
|
||||
})
|
||||
.err();
|
||||
|
||||
if let Some(panic_buf) = panic_hook::take_capture_buf() {
|
||||
let panic_buf = panic_buf.lock().unwrap_or_else(|e| e.into_inner());
|
||||
@@ -141,16 +169,17 @@ fn run_test_inner(
|
||||
write!(stderr, "{panic_buf}");
|
||||
}
|
||||
|
||||
let outcome = match (should_panic, panic_payload) {
|
||||
(ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded,
|
||||
(ShouldPanic::No, Some(_)) => TestOutcome::Failed { message: None },
|
||||
(ShouldPanic::Yes, None) => {
|
||||
TestOutcome::Failed { message: Some("test did not panic as expected") }
|
||||
// Interpret the presence/absence of a panic as test failure/success.
|
||||
let outcome = match (args.should_fail, panic_payload) {
|
||||
(ShouldFail::No, None) | (ShouldFail::Yes, Some(_)) => TestOutcome::Succeeded,
|
||||
(ShouldFail::No, Some(_)) => TestOutcome::Failed { message: None },
|
||||
(ShouldFail::Yes, None) => {
|
||||
TestOutcome::Failed { message: Some("`//@ should-fail` test did not fail as expected") }
|
||||
}
|
||||
};
|
||||
|
||||
let stdout = capture.into_inner();
|
||||
completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap();
|
||||
args.completion_sender.send(TestCompletion { id: args.id, outcome, stdout }).unwrap();
|
||||
}
|
||||
|
||||
enum CaptureKind {
|
||||
@@ -207,33 +236,6 @@ impl CaptureKind {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
struct TestId(usize);
|
||||
|
||||
struct RunnableTest {
|
||||
config: Arc<Config>,
|
||||
testpaths: TestPaths,
|
||||
revision: Option<String>,
|
||||
}
|
||||
|
||||
impl RunnableTest {
|
||||
fn new(test: &CollectedTest) -> Self {
|
||||
let config = Arc::clone(&test.config);
|
||||
let testpaths = test.testpaths.clone();
|
||||
let revision = test.revision.clone();
|
||||
Self { config, testpaths, revision }
|
||||
}
|
||||
|
||||
fn run(&self, stdout: &dyn ConsoleOut, stderr: &dyn ConsoleOut) {
|
||||
__rust_begin_short_backtrace(|| {
|
||||
crate::runtest::run(
|
||||
Arc::clone(&self.config),
|
||||
stdout,
|
||||
stderr,
|
||||
&self.testpaths,
|
||||
self.revision.as_deref(),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
|
||||
#[inline(never)]
|
||||
fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T {
|
||||
@@ -336,7 +338,7 @@ pub(crate) struct CollectedTestDesc {
|
||||
pub(crate) filterable_path: Utf8PathBuf,
|
||||
pub(crate) ignore: bool,
|
||||
pub(crate) ignore_message: Option<Cow<'static, str>>,
|
||||
pub(crate) should_panic: ShouldPanic,
|
||||
pub(crate) should_fail: ShouldFail,
|
||||
}
|
||||
|
||||
/// Whether console output should be colored or not.
|
||||
@@ -348,9 +350,10 @@ pub enum ColorConfig {
|
||||
NeverColor,
|
||||
}
|
||||
|
||||
/// Whether test is expected to panic or not.
|
||||
/// Tests with `//@ should-fail` are tests of compiletest itself, and should
|
||||
/// be reported as successful if and only if they would have _failed_.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum ShouldPanic {
|
||||
pub(crate) enum ShouldFail {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, BufReader};
|
||||
use std::process::{Child, Command, ExitStatus, Output, Stdio};
|
||||
use std::sync::Arc;
|
||||
use std::{env, fmt, iter, str};
|
||||
|
||||
use build_helper::fs::remove_and_create_dir_all;
|
||||
@@ -110,7 +109,7 @@ fn dylib_name(name: &str) -> String {
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
config: Arc<Config>,
|
||||
config: &Config,
|
||||
stdout: &dyn ConsoleOut,
|
||||
stderr: &dyn ConsoleOut,
|
||||
testpaths: &TestPaths,
|
||||
|
||||
@@ -78,9 +78,9 @@ pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {}
|
||||
// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"}
|
||||
// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"}
|
||||
// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"}
|
||||
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
|
||||
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
|
||||
// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
|
||||
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNKNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
|
||||
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNKNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
|
||||
// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNKNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
|
||||
// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"}
|
||||
// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"}
|
||||
// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"}
|
||||
|
||||
@@ -4,3 +4,18 @@ error[E0412]: cannot find type `Iter` in this scope
|
||||
LL | let x: Iter;
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
help: consider importing one of these structs
|
||||
|
|
||||
LL + use std::collections::binary_heap::Iter;
|
||||
|
|
||||
LL + use std::collections::btree_map::Iter;
|
||||
|
|
||||
LL + use std::collections::btree_set::Iter;
|
||||
|
|
||||
LL + use std::collections::hash_map::Iter;
|
||||
|
|
||||
= and 9 other candidates
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
||||
|
||||
@@ -7,5 +7,8 @@ LL | other_file::WithPrivateMethod.private_method();
|
||||
::: $DIR/auxiliary/other_file.rs:5:5
|
||||
|
|
||||
LL | fn private_method(&self) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ private method defined here
|
||||
|
|
||||
| ------------------------ private method defined here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0624`.
|
||||
|
||||
@@ -4,39 +4,90 @@ error: hello to you, too!
|
||||
LL | hello!(hi);
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: found these 'hi's
|
||||
--> $DIR/multispan.rs:15:12
|
||||
|
|
||||
LL | hello!(hi);
|
||||
| ^^
|
||||
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: hello to you, too!
|
||||
--> $DIR/multispan.rs:18:5
|
||||
|
|
||||
LL | hello!(hi hi);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: found these 'hi's
|
||||
--> $DIR/multispan.rs:18:12
|
||||
|
|
||||
LL | hello!(hi hi);
|
||||
| ^^ ^^
|
||||
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: hello to you, too!
|
||||
--> $DIR/multispan.rs:21:5
|
||||
|
|
||||
LL | hello!(hi hi hi);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: found these 'hi's
|
||||
--> $DIR/multispan.rs:21:12
|
||||
|
|
||||
LL | hello!(hi hi hi);
|
||||
| ^^ ^^ ^^
|
||||
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: hello to you, too!
|
||||
--> $DIR/multispan.rs:24:5
|
||||
|
|
||||
LL | hello!(hi hey hi yo hi beep beep hi hi);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: found these 'hi's
|
||||
--> $DIR/multispan.rs:24:12
|
||||
|
|
||||
LL | hello!(hi hey hi yo hi beep beep hi hi);
|
||||
| ^^ ^^ ^^ ^^ ^^
|
||||
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: hello to you, too!
|
||||
--> $DIR/multispan.rs:25:5
|
||||
|
|
||||
LL | hello!(hi there, hi how are you? hi... hi.);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: found these 'hi's
|
||||
--> $DIR/multispan.rs:25:12
|
||||
|
|
||||
LL | hello!(hi there, hi how are you? hi... hi.);
|
||||
| ^^ ^^ ^^ ^^
|
||||
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: hello to you, too!
|
||||
--> $DIR/multispan.rs:26:5
|
||||
|
|
||||
LL | hello!(whoah. hi di hi di ho);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: found these 'hi's
|
||||
--> $DIR/multispan.rs:26:19
|
||||
|
|
||||
LL | hello!(whoah. hi di hi di ho);
|
||||
| ^^ ^^
|
||||
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: hello to you, too!
|
||||
--> $DIR/multispan.rs:27:5
|
||||
|
|
||||
LL | hello!(hi good hi and good bye);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: found these 'hi's
|
||||
--> $DIR/multispan.rs:27:12
|
||||
|
|
||||
LL | hello!(hi good hi and good bye);
|
||||
| ^^ ^^
|
||||
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Future incompatibility report: Future breakage diagnostic:
|
||||
warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:7:1
|
||||
|
|
||||
LL | #[macro_export(hello, world)]
|
||||
@@ -9,7 +9,7 @@ LL | #[macro_export(hello, world)]
|
||||
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
|
||||
|
||||
Future breakage diagnostic:
|
||||
warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:14:1
|
||||
|
|
||||
LL | #[macro_export(not_local_inner_macros)]
|
||||
@@ -19,7 +19,7 @@ LL | #[macro_export(not_local_inner_macros)]
|
||||
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
|
||||
|
||||
Future breakage diagnostic:
|
||||
warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:31:1
|
||||
|
|
||||
LL | #[macro_export()]
|
||||
@@ -29,7 +29,7 @@ LL | #[macro_export()]
|
||||
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
|
||||
|
||||
Future breakage diagnostic:
|
||||
warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:38:1
|
||||
|
|
||||
LL | #[macro_export("blah")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:7:1
|
||||
|
|
||||
LL | #[macro_export(hello, world)]
|
||||
@@ -12,7 +12,7 @@ note: the lint level is defined here
|
||||
LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:14:1
|
||||
|
|
||||
LL | #[macro_export(not_local_inner_macros)]
|
||||
@@ -21,7 +21,7 @@ LL | #[macro_export(not_local_inner_macros)]
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
|
||||
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:31:1
|
||||
|
|
||||
LL | #[macro_export()]
|
||||
@@ -30,7 +30,7 @@ LL | #[macro_export()]
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
|
||||
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:38:1
|
||||
|
|
||||
LL | #[macro_export("blah")]
|
||||
@@ -42,7 +42,7 @@ LL | #[macro_export("blah")]
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Future incompatibility report: Future breakage diagnostic:
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:7:1
|
||||
|
|
||||
LL | #[macro_export(hello, world)]
|
||||
@@ -57,7 +57,7 @@ LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Future breakage diagnostic:
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:14:1
|
||||
|
|
||||
LL | #[macro_export(not_local_inner_macros)]
|
||||
@@ -72,7 +72,7 @@ LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Future breakage diagnostic:
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:31:1
|
||||
|
|
||||
LL | #[macro_export()]
|
||||
@@ -87,7 +87,7 @@ LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Future breakage diagnostic:
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/invalid_macro_export_argument.rs:38:1
|
||||
|
|
||||
LL | #[macro_export("blah")]
|
||||
|
||||
@@ -701,7 +701,7 @@ error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `
|
||||
LL | #[macro_use = 1]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
|
||||
error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
|
||||
--> $DIR/malformed-attrs.rs:221:1
|
||||
|
|
||||
LL | #[macro_export = 18]
|
||||
|
||||
@@ -113,7 +113,7 @@ error[E0539]: malformed `link_section` attribute input
|
||||
--> $DIR/cfg_attr-attr-syntax-validation.rs:44:18
|
||||
|
|
||||
LL | #[cfg_attr(true, link_section)]
|
||||
| ^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
|
||||
| ^^^^^^^^^^^^ help: must be of the form: `link_section = "name"`
|
||||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute>
|
||||
|
||||
@@ -129,14 +129,12 @@ LL | #[cfg_attr(true, inline())]
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #[cfg_attr(true, inline())]
|
||||
LL + #[cfg_attr(true, #[inline(always)])]
|
||||
|
|
||||
LL - #[cfg_attr(true, inline())]
|
||||
LL + #[cfg_attr(true, #[inline(never)])]
|
||||
|
|
||||
LL - #[cfg_attr(true, inline())]
|
||||
LL + #[cfg_attr(true, #[inline])]
|
||||
LL + #[cfg_attr(true, inline)]
|
||||
|
|
||||
LL | #[cfg_attr(true, inline(always))]
|
||||
| ++++++
|
||||
LL | #[cfg_attr(true, inline(never))]
|
||||
| +++++
|
||||
|
||||
warning: `#[link_section]` attribute cannot be used on structs
|
||||
--> $DIR/cfg_attr-attr-syntax-validation.rs:44:18
|
||||
|
||||
Reference in New Issue
Block a user