Auto merge of #142432 - matthiaskrgr:rollup-ziuls9y, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang/rust#138016 (Added `Clone` implementation for `ChunkBy`) - rust-lang/rust#141162 (refactor `AttributeGate` and `rustc_attr!` to emit notes during feature checking) - rust-lang/rust#141474 (Add `ParseMode::Diagnostic` and fix multiline spans in diagnostic attribute lints) - rust-lang/rust#141947 (Specify that "option-like" enums must be `#[repr(Rust)]` to be ABI-compatible with their non-1ZST field.) - rust-lang/rust#142252 (Improve clarity of `core::sync::atomic` docs about "Considerations" in regards to CAS operations) - rust-lang/rust#142337 (miri: add flag to suppress float non-determinism) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -36,6 +36,16 @@ macro_rules! gate_alt {
|
||||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
||||
for note in $notes {
|
||||
diag.note(*note);
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// The case involving a multispan.
|
||||
@@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
// Check feature gates for built-in attributes.
|
||||
if let Some(BuiltinAttribute {
|
||||
gate: AttributeGate::Gated(_, name, descr, has_feature),
|
||||
gate: AttributeGate::Gated { feature, message, check, notes, .. },
|
||||
..
|
||||
}) = attr_info
|
||||
{
|
||||
gate_alt!(self, has_feature(self.features), *name, attr.span, *descr);
|
||||
gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
|
||||
}
|
||||
// Check unstable flavors of the `#[doc]` attribute.
|
||||
if attr.has_name(sym::doc) {
|
||||
|
||||
@@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::{Features, Stability};
|
||||
use crate::Features;
|
||||
|
||||
type GateFn = fn(&Features) -> bool;
|
||||
|
||||
@@ -94,34 +94,23 @@ pub enum AttributeSafety {
|
||||
Unsafe { unsafe_since: Option<Edition> },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub enum AttributeGate {
|
||||
/// Is gated by a given feature gate, reason
|
||||
/// and function to check if enabled
|
||||
Gated(Stability, Symbol, &'static str, fn(&Features) -> bool),
|
||||
|
||||
/// A gated attribute which requires a feature gate to be enabled.
|
||||
Gated {
|
||||
/// The feature gate, for example `#![feature(rustc_attrs)]` for rustc_* attributes.
|
||||
feature: Symbol,
|
||||
/// The error message displayed when an attempt is made to use the attribute without its feature gate.
|
||||
message: &'static str,
|
||||
/// Check function to be called during the `PostExpansionVisitor` pass.
|
||||
check: fn(&Features) -> bool,
|
||||
/// Notes to be displayed when an attempt is made to use the attribute without its feature gate.
|
||||
notes: &'static [&'static str],
|
||||
},
|
||||
/// Ungated attribute, can be used on all release channels
|
||||
Ungated,
|
||||
}
|
||||
|
||||
// fn() is not Debug
|
||||
impl std::fmt::Debug for AttributeGate {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
Self::Gated(ref stab, name, expl, _) => {
|
||||
write!(fmt, "Gated({stab:?}, {name}, {expl})")
|
||||
}
|
||||
Self::Ungated => write!(fmt, "Ungated"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AttributeGate {
|
||||
fn is_deprecated(&self) -> bool {
|
||||
matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..))
|
||||
}
|
||||
}
|
||||
|
||||
/// A template that the attribute input must match.
|
||||
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
|
||||
#[derive(Clone, Copy, Default)]
|
||||
@@ -247,7 +236,7 @@ macro_rules! ungated {
|
||||
}
|
||||
|
||||
macro_rules! gated {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
@@ -255,10 +244,15 @@ macro_rules! gated {
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
|
||||
gate: Gated {
|
||||
feature: sym::$gate,
|
||||
message: $message,
|
||||
check: Features::$gate,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
@@ -266,10 +260,15 @@ macro_rules! gated {
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
|
||||
gate: Gated {
|
||||
feature: sym::$attr,
|
||||
message: $message,
|
||||
check: Features::$attr,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
@@ -277,10 +276,15 @@ macro_rules! gated {
|
||||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
|
||||
gate: Gated {
|
||||
feature: sym::$gate,
|
||||
message: $message,
|
||||
check: Features::$gate,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
@@ -288,7 +292,12 @@ macro_rules! gated {
|
||||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
|
||||
gate: Gated {
|
||||
feature: sym::$attr,
|
||||
message: $message,
|
||||
check: Features::$attr,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -304,12 +313,11 @@ macro_rules! rustc_attr {
|
||||
concat!(
|
||||
"the `#[",
|
||||
stringify!($attr),
|
||||
"]` attribute is just used for rustc unit tests \
|
||||
and will never be stable",
|
||||
"]` attribute is used for rustc unit tests"
|
||||
),
|
||||
)
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
@@ -317,7 +325,17 @@ macro_rules! rustc_attr {
|
||||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs),
|
||||
gate: Gated {
|
||||
feature: sym::rustc_attrs,
|
||||
message: "use of an internal attribute",
|
||||
check: Features::rustc_attrs,
|
||||
notes: &[
|
||||
concat!("the `#[",
|
||||
stringify!($attr),
|
||||
"]` attribute is an internal implementation detail that will never be stable"),
|
||||
$($notes),*
|
||||
]
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -328,9 +346,6 @@ macro_rules! experimental {
|
||||
};
|
||||
}
|
||||
|
||||
const IMPL_DETAIL: &str = "internal implementation detail";
|
||||
const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum EncodeCrossCrate {
|
||||
Yes,
|
||||
@@ -668,7 +683,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_attr!(
|
||||
rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"rustc_deprecated_safe_2024 is supposed to be used in libstd only",
|
||||
"`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_pub_transparent, Normal, template!(Word),
|
||||
@@ -695,7 +710,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
|
||||
never type stabilization, and will never be stable"
|
||||
never type stabilization"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
@@ -704,23 +719,23 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
|
||||
rustc_attr!(
|
||||
rustc_allocator, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_nounwind, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_reallocator, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_deallocator, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
gated!(
|
||||
default_lib_allocator, Normal, template!(Word), WarnFollowing,
|
||||
@@ -762,7 +777,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
@@ -772,11 +787,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_attr!(
|
||||
rustc_builtin_macro, Normal,
|
||||
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, IMPL_DETAIL
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_macro_transparency, Normal,
|
||||
@@ -786,7 +801,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_attr!(
|
||||
rustc_autodiff, Normal,
|
||||
template!(Word, List: r#""...""#), DuplicatesOk,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
|
||||
// The attributes are not gated, to avoid stability errors, but they cannot be used in stable
|
||||
@@ -812,54 +827,53 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
NameValueStr: "message"
|
||||
),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
INTERNAL_UNSTABLE
|
||||
"see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_confusables, Normal,
|
||||
template!(List: r#""name1", "name2", ..."#),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
INTERNAL_UNSTABLE,
|
||||
),
|
||||
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
|
||||
rustc_attr!(
|
||||
rustc_conversion_suggestion, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Prevents field reads in the marked trait or method to be considered
|
||||
// during dead code analysis.
|
||||
rustc_attr!(
|
||||
rustc_trivial_field_reads, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::potential_query_instability` lint to warn methods which
|
||||
// might not be stable during incremental compilation.
|
||||
rustc_attr!(
|
||||
rustc_lint_query_instability, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::untracked_query_information` lint to warn methods which
|
||||
// might not be stable during incremental compilation.
|
||||
rustc_attr!(
|
||||
rustc_lint_untracked_query_information, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
|
||||
// APIs. Any function with this attribute will be checked by that lint.
|
||||
rustc_attr!(
|
||||
rustc_lint_diagnostics, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
|
||||
// types (as well as any others in future).
|
||||
rustc_attr!(
|
||||
rustc_lint_opt_ty, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::bad_opt_access` lint on fields
|
||||
// types (as well as any others in future).
|
||||
rustc_attr!(
|
||||
rustc_lint_opt_deny_field_access, Normal, template!(List: "message"),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
@@ -868,28 +882,30 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
|
||||
rustc_attr!(
|
||||
rustc_promotable, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL),
|
||||
EncodeCrossCrate::No, ),
|
||||
rustc_attr!(
|
||||
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Do not const-check this function's body. It will always get replaced during CTFE.
|
||||
rustc_attr!(
|
||||
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
|
||||
),
|
||||
// Ensure the argument to this function is &&str during const-check.
|
||||
rustc_attr!(
|
||||
rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes, "`#[rustc_const_panic_str]` ensures the argument to this function is &&str during const-check",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_const_stable_indirect, Normal,
|
||||
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
|
||||
template!(Word),
|
||||
WarnFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"this is an internal implementation detail",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_intrinsic_const_stable_indirect, Normal,
|
||||
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
|
||||
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
|
||||
),
|
||||
gated!(
|
||||
rustc_allow_const_fn_unstable, Normal,
|
||||
@@ -905,21 +921,21 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
|
||||
niche optimizations in libcore and libstd and will never be stable",
|
||||
niche optimizations in the standard library",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
|
||||
niche optimizations in libcore and libstd and will never be stable",
|
||||
niche optimizations in the standard library",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
|
||||
guaranteed niche optimizations in libcore and libstd and will never be stable\n\
|
||||
(note that the compiler does not even check whether the type indeed is being non-null-optimized; \
|
||||
it is your responsibility to ensure that the attribute is only used on types that are optimized)",
|
||||
guaranteed niche optimizations in the standard library",
|
||||
"the compiler does not even check whether the type indeed is being non-null-optimized; \
|
||||
it is your responsibility to ensure that the attribute is only used on types that are optimized",
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
@@ -932,17 +948,17 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_attr!(
|
||||
rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
|
||||
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
|
||||
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
|
||||
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
@@ -950,15 +966,15 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
|
||||
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
|
||||
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
|
||||
"#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver."
|
||||
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
|
||||
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
|
||||
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
|
||||
@@ -970,7 +986,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
|
||||
"`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_do_not_implement_via_object,
|
||||
@@ -978,14 +994,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
|
||||
"`#[rustc_do_not_implement_via_object]` opts out of the automatic trait impl for trait objects \
|
||||
(`impl Trait for dyn Trait`)"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
|
||||
the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
|
||||
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
|
||||
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`."
|
||||
),
|
||||
|
||||
BuiltinAttribute {
|
||||
@@ -996,12 +1012,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
safety: AttributeSafety::Normal,
|
||||
template: template!(NameValueStr: "name"),
|
||||
duplicates: ErrorFollowing,
|
||||
gate: Gated(
|
||||
Stability::Unstable,
|
||||
sym::rustc_attrs,
|
||||
"diagnostic items compiler internal support for linting",
|
||||
Features::rustc_attrs,
|
||||
),
|
||||
gate: Gated{
|
||||
feature: sym::rustc_attrs,
|
||||
message: "use of an internal attribute",
|
||||
check: Features::rustc_attrs,
|
||||
notes: &["the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types \
|
||||
from the standard library for diagnostic purposes"],
|
||||
},
|
||||
},
|
||||
gated!(
|
||||
// Used in resolve:
|
||||
@@ -1015,14 +1032,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_attr!(
|
||||
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
|
||||
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
|
||||
overflow checking behavior of several libcore functions that are inlined \
|
||||
across crates and will never be stable",
|
||||
overflow checking behavior of several functions in the standard library that are inlined \
|
||||
across crates",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_reservation_impl, Normal,
|
||||
template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_reservation_impl]` attribute is internally used \
|
||||
for reserving for `for<T> From<!> for T` impl"
|
||||
for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
|
||||
@@ -1053,12 +1070,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
|
||||
ErrorFollowing, EncodeCrossCrate::No,
|
||||
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
|
||||
definition of a trait, it's currently in experimental form and should be changed before \
|
||||
being exposed outside of the std"
|
||||
definition of a trait. Its syntax and semantics are highly experimental and will be \
|
||||
subject to change before stabilization",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#,
|
||||
EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \
|
||||
to provide a way to generate documentation for primitive types",
|
||||
),
|
||||
gated!(
|
||||
rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
|
||||
@@ -1066,11 +1084,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
|
||||
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
|
||||
"`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
|
||||
"#[rustc_force_inline] forces a free function to be inlined"
|
||||
"`#[rustc_force_inline]` forces a free function to be inlined"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
@@ -1209,10 +1227,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
),
|
||||
];
|
||||
|
||||
pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
|
||||
BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr_name(name: Symbol) -> bool {
|
||||
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
|
||||
}
|
||||
|
||||
@@ -40,14 +40,6 @@ pub struct Feature {
|
||||
issue: Option<NonZero<u32>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Stability {
|
||||
Unstable,
|
||||
// First argument is tracking issue link; second argument is an optional
|
||||
// help message, which defaults to "remove this attribute".
|
||||
Deprecated(&'static str, Option<&'static str>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash)]
|
||||
pub enum UnstableFeatures {
|
||||
/// Disallow use of unstable features, as on beta/stable channels.
|
||||
@@ -144,9 +136,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
|
||||
pub use accepted::ACCEPTED_LANG_FEATURES;
|
||||
pub use builtin_attrs::{
|
||||
AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
|
||||
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes,
|
||||
encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
|
||||
is_valid_for_get_attr,
|
||||
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate,
|
||||
find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr,
|
||||
};
|
||||
pub use removed::REMOVED_LANG_FEATURES;
|
||||
pub use unstable::{
|
||||
|
||||
@@ -72,9 +72,6 @@ lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
|
||||
lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
|
||||
lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
|
||||
|
||||
lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
|
||||
.msg_suggestion = {$msg}
|
||||
.default_suggestion = remove this attribute
|
||||
lint_builtin_deref_nullptr = dereferencing a null pointer
|
||||
.label = this code causes undefined behavior when executed
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind};
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_errors::{Applicability, LintDiagnostic};
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes};
|
||||
use rustc_feature::GateIssue;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
|
||||
@@ -48,8 +48,7 @@ use rustc_trait_selection::traits::{self};
|
||||
|
||||
use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
|
||||
use crate::lints::{
|
||||
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
|
||||
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
|
||||
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDerefNullptr, BuiltinDoubleNegations,
|
||||
BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
|
||||
BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
|
||||
BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
|
||||
@@ -799,53 +798,6 @@ impl EarlyLintPass for AnonymousParameters {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for use of attributes which have been deprecated.
|
||||
#[derive(Clone)]
|
||||
pub struct DeprecatedAttr {
|
||||
// This is not free to compute, so we want to keep it around, rather than
|
||||
// compute it for every attribute.
|
||||
depr_attrs: Vec<&'static BuiltinAttribute>,
|
||||
}
|
||||
|
||||
impl_lint_pass!(DeprecatedAttr => []);
|
||||
|
||||
impl Default for DeprecatedAttr {
|
||||
fn default() -> Self {
|
||||
DeprecatedAttr { depr_attrs: deprecated_attributes() }
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for DeprecatedAttr {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
|
||||
if attr.ident().map(|ident| ident.name) == Some(*name) {
|
||||
if let &AttributeGate::Gated(
|
||||
Stability::Deprecated(link, suggestion),
|
||||
name,
|
||||
reason,
|
||||
_,
|
||||
) = gate
|
||||
{
|
||||
let suggestion = match suggestion {
|
||||
Some(msg) => {
|
||||
BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg }
|
||||
}
|
||||
None => {
|
||||
BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span }
|
||||
}
|
||||
};
|
||||
cx.emit_span_lint(
|
||||
DEPRECATED,
|
||||
attr.span,
|
||||
BuiltinDeprecatedAttrLink { name, reason, link, suggestion },
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
|
||||
use rustc_ast::token::CommentKind;
|
||||
|
||||
|
||||
@@ -174,7 +174,6 @@ early_lint_methods!(
|
||||
AnonymousParameters: AnonymousParameters,
|
||||
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
|
||||
NonCamelCaseTypes: NonCamelCaseTypes,
|
||||
DeprecatedAttr: DeprecatedAttr::default(),
|
||||
WhileTrue: WhileTrue,
|
||||
NonAsciiIdents: NonAsciiIdents,
|
||||
IncompleteInternalFeatures: IncompleteInternalFeatures,
|
||||
|
||||
@@ -199,32 +199,6 @@ pub(crate) struct BuiltinAnonymousParams<'a> {
|
||||
pub ty_snip: &'a str,
|
||||
}
|
||||
|
||||
// FIXME(davidtwco) translatable deprecated attr
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_deprecated_attr_link)]
|
||||
pub(crate) struct BuiltinDeprecatedAttrLink<'a> {
|
||||
pub name: Symbol,
|
||||
pub reason: &'a str,
|
||||
pub link: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
|
||||
#[suggestion(lint_msg_suggestion, code = "", applicability = "machine-applicable")]
|
||||
Msg {
|
||||
#[primary_span]
|
||||
suggestion: Span,
|
||||
msg: &'a str,
|
||||
},
|
||||
#[suggestion(lint_default_suggestion, code = "", applicability = "machine-applicable")]
|
||||
Default {
|
||||
#[primary_span]
|
||||
suggestion: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unused_doc_comment)]
|
||||
pub(crate) struct BuiltinUnusedDocComment<'a> {
|
||||
|
||||
@@ -29,58 +29,45 @@ pub enum ParseMode {
|
||||
Format,
|
||||
/// An inline assembly template string for `asm!`.
|
||||
InlineAsm,
|
||||
/// A format string for use in diagnostic attributes.
|
||||
///
|
||||
/// Similar to `format_args!`, however only named ("captured") arguments
|
||||
/// are allowed, and no format modifiers are permitted.
|
||||
Diagnostic,
|
||||
}
|
||||
|
||||
/// A piece is a portion of the format string which represents the next part
|
||||
/// to emit. These are emitted as a stream by the `Parser` class.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Piece<'a> {
|
||||
pub enum Piece<'input> {
|
||||
/// A literal string which should directly be emitted
|
||||
Lit(&'a str),
|
||||
Lit(&'input str),
|
||||
/// This describes that formatting should process the next argument (as
|
||||
/// specified inside) for emission.
|
||||
NextArgument(Box<Argument<'a>>),
|
||||
NextArgument(Box<Argument<'input>>),
|
||||
}
|
||||
|
||||
/// Representation of an argument specification.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Argument<'a> {
|
||||
pub struct Argument<'input> {
|
||||
/// Where to find this argument
|
||||
pub position: Position<'a>,
|
||||
pub position: Position<'input>,
|
||||
/// The span of the position indicator. Includes any whitespace in implicit
|
||||
/// positions (`{ }`).
|
||||
pub position_span: Range<usize>,
|
||||
/// How to format the argument
|
||||
pub format: FormatSpec<'a>,
|
||||
pub format: FormatSpec<'input>,
|
||||
}
|
||||
|
||||
impl<'a> Argument<'a> {
|
||||
impl<'input> Argument<'input> {
|
||||
pub fn is_identifier(&self) -> bool {
|
||||
matches!(self.position, Position::ArgumentNamed(_))
|
||||
&& matches!(
|
||||
self.format,
|
||||
FormatSpec {
|
||||
fill: None,
|
||||
fill_span: None,
|
||||
align: AlignUnknown,
|
||||
sign: None,
|
||||
alternate: false,
|
||||
zero_pad: false,
|
||||
debug_hex: None,
|
||||
precision: CountImplied,
|
||||
precision_span: None,
|
||||
width: CountImplied,
|
||||
width_span: None,
|
||||
ty: "",
|
||||
ty_span: None,
|
||||
},
|
||||
)
|
||||
matches!(self.position, Position::ArgumentNamed(_)) && self.format == FormatSpec::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Specification for the formatting of an argument in the format string.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct FormatSpec<'a> {
|
||||
#[derive(Clone, Debug, PartialEq, Default)]
|
||||
pub struct FormatSpec<'input> {
|
||||
/// Optionally specified character to fill alignment with.
|
||||
pub fill: Option<char>,
|
||||
/// Span of the optionally specified fill character.
|
||||
@@ -96,30 +83,30 @@ pub struct FormatSpec<'a> {
|
||||
/// The `x` or `X` flag. (Only for `Debug`.)
|
||||
pub debug_hex: Option<DebugHex>,
|
||||
/// The integer precision to use.
|
||||
pub precision: Count<'a>,
|
||||
pub precision: Count<'input>,
|
||||
/// The span of the precision formatting flag (for diagnostics).
|
||||
pub precision_span: Option<Range<usize>>,
|
||||
/// The string width requested for the resulting format.
|
||||
pub width: Count<'a>,
|
||||
pub width: Count<'input>,
|
||||
/// The span of the width formatting flag (for diagnostics).
|
||||
pub width_span: Option<Range<usize>>,
|
||||
/// The descriptor string representing the name of the format desired for
|
||||
/// this argument, this can be empty or any number of characters, although
|
||||
/// it is required to be one word.
|
||||
pub ty: &'a str,
|
||||
pub ty: &'input str,
|
||||
/// The span of the descriptor string (for diagnostics).
|
||||
pub ty_span: Option<Range<usize>>,
|
||||
}
|
||||
|
||||
/// Enum describing where an argument for a format can be located.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Position<'a> {
|
||||
pub enum Position<'input> {
|
||||
/// The argument is implied to be located at an index
|
||||
ArgumentImplicitlyIs(usize),
|
||||
/// The argument is located at a specific index given in the format,
|
||||
ArgumentIs(usize),
|
||||
/// The argument has a name.
|
||||
ArgumentNamed(&'a str),
|
||||
ArgumentNamed(&'input str),
|
||||
}
|
||||
|
||||
impl Position<'_> {
|
||||
@@ -132,7 +119,7 @@ impl Position<'_> {
|
||||
}
|
||||
|
||||
/// Enum of alignments which are supported.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
||||
pub enum Alignment {
|
||||
/// The value will be aligned to the left.
|
||||
AlignLeft,
|
||||
@@ -141,6 +128,7 @@ pub enum Alignment {
|
||||
/// The value will be aligned in the center.
|
||||
AlignCenter,
|
||||
/// The value will take on a default alignment.
|
||||
#[default]
|
||||
AlignUnknown,
|
||||
}
|
||||
|
||||
@@ -164,17 +152,18 @@ pub enum DebugHex {
|
||||
|
||||
/// A count is used for the precision and width parameters of an integer, and
|
||||
/// can reference either an argument or a literal integer.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Count<'a> {
|
||||
#[derive(Clone, Debug, PartialEq, Default)]
|
||||
pub enum Count<'input> {
|
||||
/// The count is specified explicitly.
|
||||
CountIs(u16),
|
||||
/// The count is specified by the argument with the given name.
|
||||
CountIsName(&'a str, Range<usize>),
|
||||
CountIsName(&'input str, Range<usize>),
|
||||
/// The count is specified by the argument at the given index.
|
||||
CountIsParam(usize),
|
||||
/// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
|
||||
CountIsStar(usize),
|
||||
/// The count is implied and cannot be explicitly specified.
|
||||
#[default]
|
||||
CountImplied,
|
||||
}
|
||||
|
||||
@@ -208,10 +197,10 @@ pub enum Suggestion {
|
||||
///
|
||||
/// This is a recursive-descent parser for the sake of simplicity, and if
|
||||
/// necessary there's probably lots of room for improvement performance-wise.
|
||||
pub struct Parser<'a> {
|
||||
pub struct Parser<'input> {
|
||||
mode: ParseMode,
|
||||
/// Input to be parsed
|
||||
input: &'a str,
|
||||
input: &'input str,
|
||||
/// Tuples of the span in the code snippet (input as written before being unescaped), the pos in input, and the char in input
|
||||
input_vec: Vec<(Range<usize>, usize, char)>,
|
||||
/// Index into input_vec
|
||||
@@ -237,15 +226,15 @@ pub struct Parser<'a> {
|
||||
pub line_spans: Vec<Range<usize>>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Parser<'a> {
|
||||
type Item = Piece<'a>;
|
||||
impl<'input> Iterator for Parser<'input> {
|
||||
type Item = Piece<'input>;
|
||||
|
||||
fn next(&mut self) -> Option<Piece<'a>> {
|
||||
if let Some(&(Range { start, end }, idx, ch)) = self.input_vec.get(self.input_vec_index) {
|
||||
fn next(&mut self) -> Option<Piece<'input>> {
|
||||
if let Some((Range { start, end }, idx, ch)) = self.peek() {
|
||||
match ch {
|
||||
'{' => {
|
||||
self.input_vec_index += 1;
|
||||
if let Some(&(_, i, '{')) = self.input_vec.get(self.input_vec_index) {
|
||||
if let Some((_, i, '{')) = self.peek() {
|
||||
self.input_vec_index += 1;
|
||||
// double open brace escape: "{{"
|
||||
// next state after this is either end-of-input or seen-a-brace
|
||||
@@ -254,25 +243,21 @@ impl<'a> Iterator for Parser<'a> {
|
||||
// single open brace
|
||||
self.last_open_brace = Some(start..end);
|
||||
let arg = self.argument();
|
||||
if let Some(close_brace_range) = self.consume_closing_brace(&arg) {
|
||||
self.ws();
|
||||
if let Some((close_brace_range, _)) = self.consume_pos('}') {
|
||||
if self.is_source_literal {
|
||||
self.arg_places.push(start..close_brace_range.end);
|
||||
}
|
||||
} else if let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) {
|
||||
match c {
|
||||
'?' => self.suggest_format_debug(),
|
||||
'<' | '^' | '>' => self.suggest_format_align(c),
|
||||
_ => {
|
||||
self.suggest_positional_arg_instead_of_captured_arg(arg.clone())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.missing_closing_brace(&arg);
|
||||
}
|
||||
|
||||
Some(Piece::NextArgument(Box::new(arg)))
|
||||
}
|
||||
}
|
||||
'}' => {
|
||||
self.input_vec_index += 1;
|
||||
if let Some(&(_, i, '}')) = self.input_vec.get(self.input_vec_index) {
|
||||
if let Some((_, i, '}')) = self.peek() {
|
||||
self.input_vec_index += 1;
|
||||
// double close brace escape: "}}"
|
||||
// next state after this is either end-of-input or start
|
||||
@@ -307,14 +292,14 @@ impl<'a> Iterator for Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
impl<'input> Parser<'input> {
|
||||
/// Creates a new parser for the given unescaped input string and
|
||||
/// optional code snippet (the input as written before being unescaped),
|
||||
/// where `style` is `Some(nr_hashes)` when the snippet is a raw string with that many hashes.
|
||||
/// If the input comes via `println` or `panic`, then it has a newline already appended,
|
||||
/// which is reflected in the `appended_newline` parameter.
|
||||
pub fn new(
|
||||
input: &'a str,
|
||||
input: &'input str,
|
||||
style: Option<usize>,
|
||||
snippet: Option<String>,
|
||||
appended_newline: bool,
|
||||
@@ -406,6 +391,16 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Peeks at the current position, without incrementing the pointer.
|
||||
pub fn peek(&self) -> Option<(Range<usize>, usize, char)> {
|
||||
self.input_vec.get(self.input_vec_index).cloned()
|
||||
}
|
||||
|
||||
/// Peeks at the current position + 1, without incrementing the pointer.
|
||||
pub fn peek_ahead(&self) -> Option<(Range<usize>, usize, char)> {
|
||||
self.input_vec.get(self.input_vec_index + 1).cloned()
|
||||
}
|
||||
|
||||
/// Optionally consumes the specified character. If the character is not at
|
||||
/// the current position, then the current iterator isn't moved and `false` is
|
||||
/// returned, otherwise the character is consumed and `true` is returned.
|
||||
@@ -418,27 +413,19 @@ impl<'a> Parser<'a> {
|
||||
/// returned, otherwise the character is consumed and the current position is
|
||||
/// returned.
|
||||
fn consume_pos(&mut self, ch: char) -> Option<(Range<usize>, usize)> {
|
||||
if let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) {
|
||||
if ch == *c {
|
||||
if let Some((r, i, c)) = self.peek()
|
||||
&& ch == c
|
||||
{
|
||||
self.input_vec_index += 1;
|
||||
return Some((r.clone(), *i));
|
||||
}
|
||||
return Some((r, i));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Forces consumption of the specified character. If the character is not
|
||||
/// found, an error is emitted.
|
||||
fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option<Range<usize>> {
|
||||
self.ws();
|
||||
|
||||
let (range, description) = if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index)
|
||||
{
|
||||
if *c == '}' {
|
||||
self.input_vec_index += 1;
|
||||
return Some(r.clone());
|
||||
}
|
||||
// or r.clone()?
|
||||
/// Called if a closing brace was not found.
|
||||
fn missing_closing_brace(&mut self, arg: &Argument<'_>) {
|
||||
let (range, description) = if let Some((r, _, c)) = self.peek() {
|
||||
(r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug()))
|
||||
} else {
|
||||
(
|
||||
@@ -471,7 +458,13 @@ impl<'a> Parser<'a> {
|
||||
suggestion: Suggestion::None,
|
||||
});
|
||||
|
||||
None
|
||||
if let Some((_, _, c)) = self.peek() {
|
||||
match c {
|
||||
'?' => self.suggest_format_debug(),
|
||||
'<' | '^' | '>' => self.suggest_format_align(c),
|
||||
_ => self.suggest_positional_arg_instead_of_captured_arg(arg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes all whitespace characters until the first non-whitespace character
|
||||
@@ -483,11 +476,11 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parses all of a string which is to be considered a "raw literal" in a
|
||||
/// format string. This is everything outside of the braces.
|
||||
fn string(&mut self, start: usize) -> &'a str {
|
||||
while let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) {
|
||||
fn string(&mut self, start: usize) -> &'input str {
|
||||
while let Some((r, i, c)) = self.peek() {
|
||||
match c {
|
||||
'{' | '}' => {
|
||||
return &self.input[start..*i];
|
||||
return &self.input[start..i];
|
||||
}
|
||||
'\n' if self.is_source_literal => {
|
||||
self.input_vec_index += 1;
|
||||
@@ -507,7 +500,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Parses an `Argument` structure, or what's contained within braces inside the format string.
|
||||
fn argument(&mut self) -> Argument<'a> {
|
||||
fn argument(&mut self) -> Argument<'input> {
|
||||
let start_idx = self.input_vec_index;
|
||||
|
||||
let position = self.position();
|
||||
@@ -518,6 +511,7 @@ impl<'a> Parser<'a> {
|
||||
let format = match self.mode {
|
||||
ParseMode::Format => self.format(),
|
||||
ParseMode::InlineAsm => self.inline_asm(),
|
||||
ParseMode::Diagnostic => self.diagnostic(),
|
||||
};
|
||||
|
||||
// Resolve position after parsing format spec.
|
||||
@@ -536,23 +530,19 @@ impl<'a> Parser<'a> {
|
||||
/// integer index of an argument, a named argument, or a blank string.
|
||||
/// Returns `Some(parsed_position)` if the position is not implicitly
|
||||
/// consuming a macro argument, `None` if it's the case.
|
||||
fn position(&mut self) -> Option<Position<'a>> {
|
||||
fn position(&mut self) -> Option<Position<'input>> {
|
||||
if let Some(i) = self.integer() {
|
||||
Some(ArgumentIs(i.into()))
|
||||
} else {
|
||||
match self.input_vec.get(self.input_vec_index) {
|
||||
Some((range, _, c)) if rustc_lexer::is_id_start(*c) => {
|
||||
match self.peek() {
|
||||
Some((range, _, c)) if rustc_lexer::is_id_start(c) => {
|
||||
let start = range.start;
|
||||
let word = self.word();
|
||||
|
||||
// Recover from `r#ident` in format strings.
|
||||
// FIXME: use a let chain
|
||||
if word == "r" {
|
||||
if let Some((r, _, '#')) = self.input_vec.get(self.input_vec_index) {
|
||||
if self
|
||||
.input_vec
|
||||
.get(self.input_vec_index + 1)
|
||||
.is_some_and(|(_, _, c)| rustc_lexer::is_id_start(*c))
|
||||
if word == "r"
|
||||
&& let Some((r, _, '#')) = self.peek()
|
||||
&& self.peek_ahead().is_some_and(|(_, _, c)| rustc_lexer::is_id_start(c))
|
||||
{
|
||||
self.input_vec_index += 1;
|
||||
let prefix_end = r.end;
|
||||
@@ -570,8 +560,6 @@ impl<'a> Parser<'a> {
|
||||
});
|
||||
return Some(ArgumentNamed(word));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(ArgumentNamed(word))
|
||||
}
|
||||
@@ -584,7 +572,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn input_vec_index2pos(&self, index: usize) -> usize {
|
||||
if let Some(&(_, pos, _)) = self.input_vec.get(index) { pos } else { self.input.len() }
|
||||
if let Some((_, pos, _)) = self.input_vec.get(index) { *pos } else { self.input.len() }
|
||||
}
|
||||
|
||||
fn input_vec_index2range(&self, index: usize) -> Range<usize> {
|
||||
@@ -597,33 +585,18 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parses a format specifier at the current position, returning all of the
|
||||
/// relevant information in the `FormatSpec` struct.
|
||||
fn format(&mut self) -> FormatSpec<'a> {
|
||||
let mut spec = FormatSpec {
|
||||
fill: None,
|
||||
fill_span: None,
|
||||
align: AlignUnknown,
|
||||
sign: None,
|
||||
alternate: false,
|
||||
zero_pad: false,
|
||||
debug_hex: None,
|
||||
precision: CountImplied,
|
||||
precision_span: None,
|
||||
width: CountImplied,
|
||||
width_span: None,
|
||||
ty: &self.input[..0],
|
||||
ty_span: None,
|
||||
};
|
||||
fn format(&mut self) -> FormatSpec<'input> {
|
||||
let mut spec = FormatSpec::default();
|
||||
|
||||
if !self.consume(':') {
|
||||
return spec;
|
||||
}
|
||||
|
||||
// fill character
|
||||
if let Some(&(ref r, _, c)) = self.input_vec.get(self.input_vec_index) {
|
||||
if let Some((_, _, '>' | '<' | '^')) = self.input_vec.get(self.input_vec_index + 1) {
|
||||
if let (Some((r, _, c)), Some((_, _, '>' | '<' | '^'))) = (self.peek(), self.peek_ahead()) {
|
||||
self.input_vec_index += 1;
|
||||
spec.fill = Some(c);
|
||||
spec.fill_span = Some(r.clone());
|
||||
}
|
||||
spec.fill_span = Some(r);
|
||||
}
|
||||
// Alignment
|
||||
if self.consume('<') {
|
||||
@@ -701,9 +674,8 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
} else if let Some((range, _)) = self.consume_pos('?') {
|
||||
spec.ty = "?";
|
||||
if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) {
|
||||
match c {
|
||||
'#' | 'x' | 'X' => self.errors.insert(
|
||||
if let Some((r, _, c @ ('#' | 'x' | 'X'))) = self.peek() {
|
||||
self.errors.insert(
|
||||
0,
|
||||
ParseError {
|
||||
description: format!("expected `}}`, found `{c}`"),
|
||||
@@ -716,9 +688,7 @@ impl<'a> Parser<'a> {
|
||||
format!("{c}?"),
|
||||
),
|
||||
},
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
spec.ty = self.word();
|
||||
@@ -733,22 +703,9 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parses an inline assembly template modifier at the current position, returning the modifier
|
||||
/// in the `ty` field of the `FormatSpec` struct.
|
||||
fn inline_asm(&mut self) -> FormatSpec<'a> {
|
||||
let mut spec = FormatSpec {
|
||||
fill: None,
|
||||
fill_span: None,
|
||||
align: AlignUnknown,
|
||||
sign: None,
|
||||
alternate: false,
|
||||
zero_pad: false,
|
||||
debug_hex: None,
|
||||
precision: CountImplied,
|
||||
precision_span: None,
|
||||
width: CountImplied,
|
||||
width_span: None,
|
||||
ty: &self.input[..0],
|
||||
ty_span: None,
|
||||
};
|
||||
fn inline_asm(&mut self) -> FormatSpec<'input> {
|
||||
let mut spec = FormatSpec::default();
|
||||
|
||||
if !self.consume(':') {
|
||||
return spec;
|
||||
}
|
||||
@@ -764,10 +721,26 @@ impl<'a> Parser<'a> {
|
||||
spec
|
||||
}
|
||||
|
||||
/// Always returns an empty `FormatSpec`
|
||||
fn diagnostic(&mut self) -> FormatSpec<'input> {
|
||||
let mut spec = FormatSpec::default();
|
||||
|
||||
let Some((Range { start, .. }, start_idx)) = self.consume_pos(':') else {
|
||||
return spec;
|
||||
};
|
||||
|
||||
spec.ty = self.string(start_idx);
|
||||
spec.ty_span = {
|
||||
let end = self.input_vec_index2range(self.input_vec_index).start;
|
||||
Some(start..end)
|
||||
};
|
||||
spec
|
||||
}
|
||||
|
||||
/// Parses a `Count` parameter at the current position. This does not check
|
||||
/// for 'CountIsNextParam' because that is only used in precision, not
|
||||
/// width.
|
||||
fn count(&mut self) -> Count<'a> {
|
||||
fn count(&mut self) -> Count<'input> {
|
||||
if let Some(i) = self.integer() {
|
||||
if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) }
|
||||
} else {
|
||||
@@ -786,10 +759,10 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parses a word starting at the current position. A word is the same as a
|
||||
/// Rust identifier, except that it can't start with `_` character.
|
||||
fn word(&mut self) -> &'a str {
|
||||
fn word(&mut self) -> &'input str {
|
||||
let index = self.input_vec_index;
|
||||
match self.input_vec.get(self.input_vec_index) {
|
||||
Some(&(ref r, i, c)) if rustc_lexer::is_id_start(c) => {
|
||||
match self.peek() {
|
||||
Some((ref r, i, c)) if rustc_lexer::is_id_start(c) => {
|
||||
self.input_vec_index += 1;
|
||||
(r.start, i)
|
||||
}
|
||||
@@ -798,7 +771,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
};
|
||||
let (err_end, end): (usize, usize) = loop {
|
||||
if let Some(&(ref r, i, c)) = self.input_vec.get(self.input_vec_index) {
|
||||
if let Some((ref r, i, c)) = self.peek() {
|
||||
if rustc_lexer::is_id_continue(c) {
|
||||
self.input_vec_index += 1;
|
||||
} else {
|
||||
@@ -828,7 +801,7 @@ impl<'a> Parser<'a> {
|
||||
let mut found = false;
|
||||
let mut overflow = false;
|
||||
let start_index = self.input_vec_index;
|
||||
while let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) {
|
||||
while let Some((_, _, c)) = self.peek() {
|
||||
if let Some(i) = c.to_digit(10) {
|
||||
self.input_vec_index += 1;
|
||||
let (tmp, mul_overflow) = cur.overflowing_mul(10);
|
||||
@@ -897,7 +870,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) {
|
||||
fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: &Argument<'_>) {
|
||||
// If the argument is not an identifier, it is not a field access.
|
||||
if !arg.is_identifier() {
|
||||
return;
|
||||
|
||||
@@ -553,3 +553,45 @@ fn asm_concat() {
|
||||
assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]);
|
||||
assert_eq!(parser.line_spans, &[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diagnostic_format_flags() {
|
||||
let lit = "{thing:blah}";
|
||||
let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic);
|
||||
assert!(!parser.is_source_literal);
|
||||
|
||||
let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() };
|
||||
|
||||
assert_eq!(
|
||||
**arg,
|
||||
Argument {
|
||||
position: ArgumentNamed("thing"),
|
||||
position_span: 2..7,
|
||||
format: FormatSpec { ty: ":blah", ty_span: Some(7..12), ..Default::default() },
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(parser.line_spans, &[]);
|
||||
assert!(parser.errors.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diagnostic_format_mod() {
|
||||
let lit = "{thing:+}";
|
||||
let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic);
|
||||
assert!(!parser.is_source_literal);
|
||||
|
||||
let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() };
|
||||
|
||||
assert_eq!(
|
||||
**arg,
|
||||
Argument {
|
||||
position: ArgumentNamed("thing"),
|
||||
position_span: 2..7,
|
||||
format: FormatSpec { ty: ":+", ty_span: Some(7..9), ..Default::default() },
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(parser.line_spans, &[]);
|
||||
assert!(parser.errors.is_empty());
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::Session;
|
||||
use crate::config::{Cfg, CheckCfg};
|
||||
@@ -192,8 +192,11 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
|
||||
} else {
|
||||
err.subdiagnostic(FeatureDiagnosticHelp { feature });
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.ui_testing {
|
||||
if feature == sym::rustc_attrs {
|
||||
// We're unlikely to stabilize something out of `rustc_attrs`
|
||||
// without at least renaming it, so pointing out how old
|
||||
// the compiler is will do little good.
|
||||
} else if sess.opts.unstable_opts.ui_testing {
|
||||
err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
|
||||
} else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
|
||||
err.subdiagnostic(suggestion);
|
||||
|
||||
@@ -810,7 +810,8 @@ impl<'tcx> OnUnimplementedFormatString {
|
||||
|
||||
let mut result = Ok(());
|
||||
|
||||
match FormatString::parse(self.symbol, self.span, &ctx) {
|
||||
let snippet = tcx.sess.source_map().span_to_snippet(self.span).ok();
|
||||
match FormatString::parse(self.symbol, snippet, self.span, &ctx) {
|
||||
// Warnings about format specifiers, deprecated parameters, wrong parameters etc.
|
||||
// In other words we'd like to let the author know, but we can still try to format the string later
|
||||
Ok(FormatString { warnings, .. }) => {
|
||||
@@ -848,14 +849,13 @@ impl<'tcx> OnUnimplementedFormatString {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Errors from the underlying `rustc_parse_format::Parser`
|
||||
Err(errors) => {
|
||||
// Error from the underlying `rustc_parse_format::Parser`
|
||||
Err(e) => {
|
||||
// we cannot return errors from processing the format string as hard error here
|
||||
// as the diagnostic namespace guarantees that malformed input cannot cause an error
|
||||
//
|
||||
// if we encounter any error while processing we nevertheless want to show it as warning
|
||||
// so that users are aware that something is not correct
|
||||
for e in errors {
|
||||
if self.is_diagnostic_namespace_variant {
|
||||
if let Some(trait_def_id) = trait_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
@@ -866,19 +866,13 @@ impl<'tcx> OnUnimplementedFormatString {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let reported = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
self.span,
|
||||
E0231,
|
||||
"{}",
|
||||
e.description,
|
||||
)
|
||||
let reported =
|
||||
struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,)
|
||||
.emit();
|
||||
result = Err(reported);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
@@ -896,7 +890,8 @@ impl<'tcx> OnUnimplementedFormatString {
|
||||
Ctx::RustcOnUnimplemented { tcx, trait_def_id }
|
||||
};
|
||||
|
||||
if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) {
|
||||
// No point passing a snippet here, we already did that in `verify`
|
||||
if let Ok(s) = FormatString::parse(self.symbol, None, self.span, &ctx) {
|
||||
s.format(args)
|
||||
} else {
|
||||
// we cannot return errors from processing the format string as hard error here
|
||||
|
||||
@@ -198,7 +198,7 @@ enum LitOrArg {
|
||||
|
||||
impl FilterFormatString {
|
||||
fn parse(input: Symbol) -> Self {
|
||||
let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format)
|
||||
let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic)
|
||||
.map(|p| match p {
|
||||
Piece::Lit(s) => LitOrArg::Lit(s.to_owned()),
|
||||
// We just ignore formatspecs here
|
||||
|
||||
@@ -5,12 +5,11 @@ use errors::*;
|
||||
use rustc_middle::ty::print::TraitRefPrintSugared;
|
||||
use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
|
||||
use rustc_parse_format::{
|
||||
Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece,
|
||||
Position,
|
||||
Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
|
||||
};
|
||||
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym};
|
||||
use rustc_span::{InnerSpan, Span, Symbol, kw, sym};
|
||||
|
||||
/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
|
||||
/// either as string pieces or dynamic arguments.
|
||||
@@ -160,32 +159,32 @@ impl FormatString {
|
||||
|
||||
pub fn parse<'tcx>(
|
||||
input: Symbol,
|
||||
snippet: Option<String>,
|
||||
span: Span,
|
||||
ctx: &Ctx<'tcx>,
|
||||
) -> Result<Self, Vec<ParseError>> {
|
||||
) -> Result<Self, ParseError> {
|
||||
let s = input.as_str();
|
||||
let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
|
||||
let mut pieces = Vec::new();
|
||||
let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic);
|
||||
let pieces: Vec<_> = parser.by_ref().collect();
|
||||
|
||||
if let Some(err) = parser.errors.into_iter().next() {
|
||||
return Err(err);
|
||||
}
|
||||
let mut warnings = Vec::new();
|
||||
|
||||
for piece in &mut parser {
|
||||
match piece {
|
||||
RpfPiece::Lit(lit) => {
|
||||
pieces.push(Piece::Lit(lit.into()));
|
||||
}
|
||||
let pieces = pieces
|
||||
.into_iter()
|
||||
.map(|piece| match piece {
|
||||
RpfPiece::Lit(lit) => Piece::Lit(lit.into()),
|
||||
RpfPiece::NextArgument(arg) => {
|
||||
warn_on_format_spec(arg.format.clone(), &mut warnings, span);
|
||||
let arg = parse_arg(&arg, ctx, &mut warnings, span);
|
||||
pieces.push(Piece::Arg(arg));
|
||||
}
|
||||
}
|
||||
warn_on_format_spec(&arg.format, &mut warnings, span, parser.is_source_literal);
|
||||
let arg = parse_arg(&arg, ctx, &mut warnings, span, parser.is_source_literal);
|
||||
Piece::Arg(arg)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if parser.errors.is_empty() {
|
||||
Ok(FormatString { input, pieces, span, warnings })
|
||||
} else {
|
||||
Err(parser.errors)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(&self, args: &FormatArgs<'_>) -> String {
|
||||
@@ -229,11 +228,12 @@ fn parse_arg<'tcx>(
|
||||
ctx: &Ctx<'tcx>,
|
||||
warnings: &mut Vec<FormatWarning>,
|
||||
input_span: Span,
|
||||
is_source_literal: bool,
|
||||
) -> FormatArg {
|
||||
let (Ctx::RustcOnUnimplemented { tcx, trait_def_id }
|
||||
| Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx;
|
||||
|
||||
let span = slice_span(input_span, arg.position_span.clone());
|
||||
let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
|
||||
|
||||
match arg.position {
|
||||
// Something like "hello {name}"
|
||||
@@ -283,39 +283,24 @@ fn parse_arg<'tcx>(
|
||||
|
||||
/// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything
|
||||
/// with specifiers, so emit a warning if they are used.
|
||||
fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) {
|
||||
if !matches!(
|
||||
spec,
|
||||
FormatSpec {
|
||||
fill: None,
|
||||
fill_span: None,
|
||||
align: Alignment::AlignUnknown,
|
||||
sign: None,
|
||||
alternate: false,
|
||||
zero_pad: false,
|
||||
debug_hex: None,
|
||||
precision: Count::CountImplied,
|
||||
precision_span: None,
|
||||
width: Count::CountImplied,
|
||||
width_span: None,
|
||||
ty: _,
|
||||
ty_span: _,
|
||||
},
|
||||
) {
|
||||
let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span);
|
||||
fn warn_on_format_spec(
|
||||
spec: &FormatSpec<'_>,
|
||||
warnings: &mut Vec<FormatWarning>,
|
||||
input_span: Span,
|
||||
is_source_literal: bool,
|
||||
) {
|
||||
if spec.ty != "" {
|
||||
let span = spec
|
||||
.ty_span
|
||||
.as_ref()
|
||||
.map(|inner| slice_span(input_span, inner.clone(), is_source_literal))
|
||||
.unwrap_or(input_span);
|
||||
warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() })
|
||||
}
|
||||
}
|
||||
|
||||
fn slice_span(input: Span, range: Range<usize>) -> Span {
|
||||
let span = input.data();
|
||||
|
||||
Span::new(
|
||||
span.lo + BytePos::from_usize(range.start),
|
||||
span.lo + BytePos::from_usize(range.end),
|
||||
span.ctxt,
|
||||
span.parent,
|
||||
)
|
||||
fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span {
|
||||
if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input }
|
||||
}
|
||||
|
||||
pub mod errors {
|
||||
|
||||
@@ -1636,6 +1636,19 @@ fn test_chunk_by() {
|
||||
assert_eq!(iter.next_back(), Some(&[1][..]));
|
||||
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
|
||||
let mut iter = slice.chunk_by(|a, b| a == b);
|
||||
assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
|
||||
assert_eq!(iter.next(), Some(&[3, 3][..]));
|
||||
let mut iter_clone = iter.clone();
|
||||
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
|
||||
assert_eq!(iter.next(), Some(&[1][..]));
|
||||
assert_eq!(iter.next(), Some(&[0][..]));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter_clone.next(), Some(&[2, 2, 2][..]));
|
||||
assert_eq!(iter_clone.next(), Some(&[1][..]));
|
||||
assert_eq!(iter_clone.next(), Some(&[0][..]));
|
||||
assert_eq!(iter_clone.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1847,6 +1847,8 @@ mod prim_ref {}
|
||||
/// - If `T` is guaranteed to be subject to the [null pointer
|
||||
/// optimization](option/index.html#representation), and `E` is an enum satisfying the following
|
||||
/// requirements, then `T` and `E` are ABI-compatible. Such an enum `E` is called "option-like".
|
||||
/// - The enum `E` uses the [`Rust` representation], and is not modified by the `align` or
|
||||
/// `packed` representation modifiers.
|
||||
/// - The enum `E` has exactly two variants.
|
||||
/// - One variant has exactly one field, of type `T`.
|
||||
/// - All fields of the other variant are zero-sized with 1-byte alignment.
|
||||
@@ -1920,6 +1922,7 @@ mod prim_ref {}
|
||||
/// [`Pointer`]: fmt::Pointer
|
||||
/// [`UnwindSafe`]: panic::UnwindSafe
|
||||
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
|
||||
/// [`Rust` representation]: <https://doc.rust-lang.org/reference/type-layout.html#the-rust-representation>
|
||||
///
|
||||
/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
|
||||
/// these traits are specially known to the compiler.
|
||||
|
||||
@@ -3376,6 +3376,13 @@ where
|
||||
#[stable(feature = "slice_group_by", since = "1.77.0")]
|
||||
impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {}
|
||||
|
||||
#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { slice: self.slice, predicate: self.predicate.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "slice_group_by", since = "1.77.0")]
|
||||
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
||||
@@ -891,6 +891,19 @@ impl AtomicBool {
|
||||
/// Err(false));
|
||||
/// assert_eq!(some_bool.load(Ordering::Relaxed), false);
|
||||
/// ```
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
|
||||
/// of CAS operations. In particular, a load of the value followed by a successful
|
||||
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
|
||||
/// changed the value in the interim. This is usually important when the *equality* check in
|
||||
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
|
||||
/// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
|
||||
/// [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
#[inline]
|
||||
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
||||
#[doc(alias = "compare_and_swap")]
|
||||
@@ -973,6 +986,19 @@ impl AtomicBool {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
|
||||
/// of CAS operations. In particular, a load of the value followed by a successful
|
||||
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
|
||||
/// changed the value in the interim. This is usually important when the *equality* check in
|
||||
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
|
||||
/// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
|
||||
/// [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
#[inline]
|
||||
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
||||
#[doc(alias = "compare_and_swap")]
|
||||
@@ -1271,11 +1297,14 @@ impl AtomicBool {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -1338,11 +1367,14 @@ impl AtomicBool {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -1393,11 +1425,14 @@ impl AtomicBool {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -1825,6 +1860,20 @@ impl<T> AtomicPtr<T> {
|
||||
/// let value = some_ptr.compare_exchange(ptr, other_ptr,
|
||||
/// Ordering::SeqCst, Ordering::Relaxed);
|
||||
/// ```
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
|
||||
/// of CAS operations. In particular, a load of the value followed by a successful
|
||||
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
|
||||
/// changed the value in the interim. This is usually important when the *equality* check in
|
||||
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
|
||||
/// does not necessarily imply identity. This is a particularly common case for pointers, as
|
||||
/// a pointer holding the same address does not imply that the same object exists at that
|
||||
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
#[inline]
|
||||
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
@@ -1874,6 +1923,20 @@ impl<T> AtomicPtr<T> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
|
||||
/// of CAS operations. In particular, a load of the value followed by a successful
|
||||
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
|
||||
/// changed the value in the interim. This is usually important when the *equality* check in
|
||||
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
|
||||
/// does not necessarily imply identity. This is a particularly common case for pointers, as
|
||||
/// a pointer holding the same address does not imply that the same object exists at that
|
||||
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
#[inline]
|
||||
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
@@ -1917,11 +1980,15 @@ impl<T> AtomicPtr<T> {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
|
||||
/// which is a particularly common pitfall for pointers!
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -1992,11 +2059,15 @@ impl<T> AtomicPtr<T> {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
|
||||
/// which is a particularly common pitfall for pointers!
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -2057,11 +2128,15 @@ impl<T> AtomicPtr<T> {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
|
||||
/// which is a particularly common pitfall for pointers!
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -2967,6 +3042,20 @@ macro_rules! atomic_int {
|
||||
/// Err(10));
|
||||
/// assert_eq!(some_var.load(Ordering::Relaxed), 10);
|
||||
/// ```
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
|
||||
/// of CAS operations. In particular, a load of the value followed by a successful
|
||||
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
|
||||
/// changed the value in the interim! This is usually important when the *equality* check in
|
||||
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
|
||||
/// does not necessarily imply identity. This is a particularly common case for pointers, as
|
||||
/// a pointer holding the same address does not imply that the same object exists at that
|
||||
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
#[inline]
|
||||
#[$stable_cxchg]
|
||||
#[$cfg_cas]
|
||||
@@ -3016,6 +3105,20 @@ macro_rules! atomic_int {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
|
||||
/// of CAS operations. In particular, a load of the value followed by a successful
|
||||
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
|
||||
/// changed the value in the interim. This is usually important when the *equality* check in
|
||||
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
|
||||
/// does not necessarily imply identity. This is a particularly common case for pointers, as
|
||||
/// a pointer holding the same address does not imply that the same object exists at that
|
||||
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
#[inline]
|
||||
#[$stable_cxchg]
|
||||
#[$cfg_cas]
|
||||
@@ -3246,13 +3349,16 @@ macro_rules! atomic_int {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
|
||||
/// and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
|
||||
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
|
||||
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -3309,13 +3415,16 @@ macro_rules! atomic_int {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
|
||||
/// and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
|
||||
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
|
||||
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -3367,13 +3476,17 @@ macro_rules! atomic_int {
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
|
||||
/// and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
/// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
/// This method is not magic; it is not provided by the hardware, and does not act like a
|
||||
/// critical section or mutex.
|
||||
///
|
||||
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
|
||||
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
|
||||
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
|
||||
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
||||
@@ -286,6 +286,11 @@ environment variable. We first document the most relevant and most commonly used
|
||||
specific circumstances, but Miri's behavior will also be more stable across versions and targets.
|
||||
This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0
|
||||
-Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`.
|
||||
* `-Zmiri-deterministic-floats` makes Miri's floating-point behavior fully deterministic. This means
|
||||
that operations will always return the preferred NaN, imprecise operations will not have any
|
||||
random error applied to them, and `min`/`max` as "maybe fused" multiply-add all behave
|
||||
deterministically. Note that Miri still uses host floats for some operations, so behavior can
|
||||
still differ depending on the host target and setup.
|
||||
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
|
||||
the program has access to host resources such as environment variables, file
|
||||
systems, and randomness.
|
||||
|
||||
@@ -601,6 +601,8 @@ fn main() {
|
||||
miri_config.collect_leak_backtraces = false;
|
||||
} else if arg == "-Zmiri-force-intrinsic-fallback" {
|
||||
miri_config.force_intrinsic_fallback = true;
|
||||
} else if arg == "-Zmiri-deterministic-floats" {
|
||||
miri_config.float_nondet = false;
|
||||
} else if arg == "-Zmiri-strict-provenance" {
|
||||
miri_config.provenance_mode = ProvenanceMode::Strict;
|
||||
} else if arg == "-Zmiri-permissive-provenance" {
|
||||
|
||||
@@ -166,6 +166,8 @@ pub struct MiriConfig {
|
||||
pub fixed_scheduling: bool,
|
||||
/// Always prefer the intrinsic fallback body over the native Miri implementation.
|
||||
pub force_intrinsic_fallback: bool,
|
||||
/// Whether floating-point operations can behave non-deterministically.
|
||||
pub float_nondet: bool,
|
||||
}
|
||||
|
||||
impl Default for MiriConfig {
|
||||
@@ -205,6 +207,7 @@ impl Default for MiriConfig {
|
||||
address_reuse_cross_thread_rate: 0.1,
|
||||
fixed_scheduling: false,
|
||||
force_intrinsic_fallback: false,
|
||||
float_nondet: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
let a = this.read_scalar(a)?.to_f32()?;
|
||||
let b = this.read_scalar(b)?.to_f32()?;
|
||||
let c = this.read_scalar(c)?.to_f32()?;
|
||||
let fuse: bool = this.machine.rng.get_mut().random();
|
||||
let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
|
||||
let res = if fuse {
|
||||
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
|
||||
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
|
||||
@@ -308,7 +308,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
let a = this.read_scalar(a)?.to_f64()?;
|
||||
let b = this.read_scalar(b)?.to_f64()?;
|
||||
let c = this.read_scalar(c)?.to_f64()?;
|
||||
let fuse: bool = this.machine.rng.get_mut().random();
|
||||
let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
|
||||
let res = if fuse {
|
||||
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
|
||||
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
|
||||
|
||||
@@ -306,7 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
let c = this.read_scalar(&this.project_index(&c, i)?)?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().random();
|
||||
let fuse: bool = intrinsic_name == "fma"
|
||||
|| (this.machine.float_nondet && this.machine.rng.get_mut().random());
|
||||
|
||||
// Works for f32 and f64.
|
||||
// FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468.
|
||||
|
||||
@@ -618,6 +618,9 @@ pub struct MiriMachine<'tcx> {
|
||||
|
||||
/// Always prefer the intrinsic fallback body over the native Miri implementation.
|
||||
pub force_intrinsic_fallback: bool,
|
||||
|
||||
/// Whether floating-point operations can behave non-deterministically.
|
||||
pub float_nondet: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> MiriMachine<'tcx> {
|
||||
@@ -778,6 +781,7 @@ impl<'tcx> MiriMachine<'tcx> {
|
||||
int2ptr_warned: Default::default(),
|
||||
mangle_internal_symbol_cache: Default::default(),
|
||||
force_intrinsic_fallback: config.force_intrinsic_fallback,
|
||||
float_nondet: config.float_nondet,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,6 +960,7 @@ impl VisitProvenance for MiriMachine<'_> {
|
||||
int2ptr_warned: _,
|
||||
mangle_internal_symbol_cache: _,
|
||||
force_intrinsic_fallback: _,
|
||||
float_nondet: _,
|
||||
} = self;
|
||||
|
||||
threads.visit_provenance(visit);
|
||||
|
||||
@@ -15,6 +15,10 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
|
||||
val: F,
|
||||
err_scale: i32,
|
||||
) -> F {
|
||||
if !ecx.machine.float_nondet {
|
||||
return val;
|
||||
}
|
||||
|
||||
let rng = ecx.machine.rng.get_mut();
|
||||
// Generate a random integer in the range [0, 2^PREC).
|
||||
// (When read as binary, the position of the first `1` determines the exponent,
|
||||
|
||||
@@ -76,6 +76,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
}
|
||||
|
||||
fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 {
|
||||
let this = self.eval_context_ref();
|
||||
if !this.machine.float_nondet {
|
||||
return F2::NAN;
|
||||
}
|
||||
|
||||
/// Make the given NaN a signaling NaN.
|
||||
/// Returns `None` if this would not result in a NaN.
|
||||
fn make_signaling<F: Float>(f: F) -> Option<F> {
|
||||
@@ -89,7 +94,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
if f.is_nan() { Some(f) } else { None }
|
||||
}
|
||||
|
||||
let this = self.eval_context_ref();
|
||||
let mut rand = this.machine.rng.borrow_mut();
|
||||
// Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation.
|
||||
// On some targets there are more possibilities; for now we just generate those options that
|
||||
@@ -118,6 +122,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
|
||||
fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F {
|
||||
let this = self.eval_context_ref();
|
||||
if !this.machine.float_nondet {
|
||||
return a;
|
||||
}
|
||||
// Return one side non-deterministically.
|
||||
let mut rand = this.machine.rng.borrow_mut();
|
||||
if rand.random() { a } else { b }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#[rustc_do_not_const_check]
|
||||
//~^ ERROR this is an internal attribute that will never be stable
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE `#[rustc_do_not_const_check]` skips const-check for this function's body
|
||||
const fn foo() {}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
error[E0658]: this is an internal attribute that will never be stable
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/gate-do-not-const-check.rs:1:1
|
||||
|
|
||||
LL | #[rustc_do_not_const_check]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable
|
||||
= note: `#[rustc_do_not_const_check]` skips const-check for this function's body
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
55
tests/ui/diagnostic_namespace/multiline_spans.rs
Normal file
55
tests/ui/diagnostic_namespace/multiline_spans.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
#![crate_type = "lib"]
|
||||
#![deny(unknown_or_malformed_diagnostic_attributes)]
|
||||
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
multiline string \
|
||||
{unknown}")]
|
||||
//~^ ERROR there is no parameter `unknown` on trait `MultiLine` [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLine {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
multiline string {unknown}")]
|
||||
//~^ ERROR there is no parameter `unknown` on trait `MultiLine2` [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLine2 {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
multiline string {unknown}")]
|
||||
//~^ ERROR there is no parameter `unknown` on trait `MultiLine3` [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLine3 {}
|
||||
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
multiline string {unknown}")]
|
||||
//~^ ERROR there is no parameter `unknown` on trait `MultiLine4` [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLine4 {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
multiline string \
|
||||
{Self:+}")]
|
||||
//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLineFmt {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
multiline string {Self:X}")]
|
||||
//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLineFmt2 {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
multiline string {Self:#}")]
|
||||
//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLineFmt3 {}
|
||||
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "here is a big \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
multiline string {Self:?}")]
|
||||
//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
pub trait MultiLineFmt4 {}
|
||||
71
tests/ui/diagnostic_namespace/multiline_spans.stderr
Normal file
71
tests/ui/diagnostic_namespace/multiline_spans.stderr
Normal file
@@ -0,0 +1,71 @@
|
||||
error: there is no parameter `unknown` on trait `MultiLine`
|
||||
--> $DIR/multiline_spans.rs:7:43
|
||||
|
|
||||
LL | ... {unknown}")]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: expect either a generic argument name or `{Self}` as format argument
|
||||
note: the lint level is defined here
|
||||
--> $DIR/multiline_spans.rs:2:9
|
||||
|
|
||||
LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: there is no parameter `unknown` on trait `MultiLine2`
|
||||
--> $DIR/multiline_spans.rs:12:60
|
||||
|
|
||||
LL | ... multiline string {unknown}")]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: expect either a generic argument name or `{Self}` as format argument
|
||||
|
||||
error: there is no parameter `unknown` on trait `MultiLine3`
|
||||
--> $DIR/multiline_spans.rs:17:23
|
||||
|
|
||||
LL | multiline string {unknown}")]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: expect either a generic argument name or `{Self}` as format argument
|
||||
|
||||
error: there is no parameter `unknown` on trait `MultiLine4`
|
||||
--> $DIR/multiline_spans.rs:27:23
|
||||
|
|
||||
LL | multiline string {unknown}")]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: expect either a generic argument name or `{Self}` as format argument
|
||||
|
||||
error: invalid format specifier
|
||||
--> $DIR/multiline_spans.rs:33:47
|
||||
|
|
||||
LL | ... {Self:+}")]
|
||||
| ^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
error: invalid format specifier
|
||||
--> $DIR/multiline_spans.rs:38:64
|
||||
|
|
||||
LL | ... multiline string {Self:X}")]
|
||||
| ^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
error: invalid format specifier
|
||||
--> $DIR/multiline_spans.rs:43:27
|
||||
|
|
||||
LL | multiline string {Self:#}")]
|
||||
| ^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
error: invalid format specifier
|
||||
--> $DIR/multiline_spans.rs:53:27
|
||||
|
|
||||
LL | multiline string {Self:?}")]
|
||||
| ^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
@@ -12,6 +12,8 @@ trait ImportantTrait2 {}
|
||||
#[diagnostic::on_unimplemented(message = "Test {1:}")]
|
||||
//~^WARN positional format arguments are not allowed here
|
||||
//~|WARN positional format arguments are not allowed here
|
||||
//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
trait ImportantTrait3 {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "Test {Self:123}")]
|
||||
@@ -20,17 +22,22 @@ trait ImportantTrait3 {}
|
||||
trait ImportantTrait4 {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "Test {Self:!}")]
|
||||
//~^WARN expected `}`, found `!`
|
||||
//~|WARN expected `}`, found `!`
|
||||
//~|WARN unmatched `}` found
|
||||
//~|WARN unmatched `}` found
|
||||
//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
trait ImportantTrait5 {}
|
||||
|
||||
#[diagnostic::on_unimplemented(message = "Test {Self:}")]
|
||||
//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
|
||||
trait ImportantTrait6 {}
|
||||
|
||||
|
||||
fn check_1(_: impl ImportantTrait1) {}
|
||||
fn check_2(_: impl ImportantTrait2) {}
|
||||
fn check_3(_: impl ImportantTrait3) {}
|
||||
fn check_4(_: impl ImportantTrait4) {}
|
||||
fn check_5(_: impl ImportantTrait5) {}
|
||||
fn check_6(_: impl ImportantTrait6) {}
|
||||
|
||||
fn main() {
|
||||
check_1(());
|
||||
@@ -42,5 +49,7 @@ fn main() {
|
||||
check_4(());
|
||||
//~^ERROR Test ()
|
||||
check_5(());
|
||||
//~^ERROR Test {Self:!}
|
||||
//~^ERROR Test ()
|
||||
check_6(());
|
||||
//~^ERROR Test ()
|
||||
}
|
||||
|
||||
@@ -14,6 +14,14 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")]
|
||||
|
|
||||
= help: only named format arguments with the name of one of the generic types are allowed in this context
|
||||
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:12:50
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
|
||||
| ^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
warning: positional format arguments are not allowed here
|
||||
--> $DIR/broken_format.rs:12:49
|
||||
|
|
||||
@@ -23,24 +31,28 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
|
||||
= help: only named format arguments with the name of one of the generic types are allowed in this context
|
||||
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:17:42
|
||||
--> $DIR/broken_format.rs:19:53
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
warning: expected `}`, found `!`
|
||||
--> $DIR/broken_format.rs:22:42
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:24:53
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| ^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
warning: unmatched `}` found
|
||||
--> $DIR/broken_format.rs:22:42
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:29:53
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")]
|
||||
| ^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
|
||||
warning: unmatched `}` found
|
||||
--> $DIR/broken_format.rs:2:42
|
||||
@@ -51,7 +63,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: {{Test } thing
|
||||
--> $DIR/broken_format.rs:36:13
|
||||
--> $DIR/broken_format.rs:43:13
|
||||
|
|
||||
LL | check_1(());
|
||||
| ------- ^^ the trait `ImportantTrait1` is not implemented for `()`
|
||||
@@ -64,7 +76,7 @@ help: this trait has no implementations, consider adding one
|
||||
LL | trait ImportantTrait1 {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `check_1`
|
||||
--> $DIR/broken_format.rs:29:20
|
||||
--> $DIR/broken_format.rs:35:20
|
||||
|
|
||||
LL | fn check_1(_: impl ImportantTrait1) {}
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `check_1`
|
||||
@@ -79,7 +91,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")]
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: Test {}
|
||||
--> $DIR/broken_format.rs:38:13
|
||||
--> $DIR/broken_format.rs:45:13
|
||||
|
|
||||
LL | check_2(());
|
||||
| ------- ^^ the trait `ImportantTrait2` is not implemented for `()`
|
||||
@@ -92,11 +104,20 @@ help: this trait has no implementations, consider adding one
|
||||
LL | trait ImportantTrait2 {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `check_2`
|
||||
--> $DIR/broken_format.rs:30:20
|
||||
--> $DIR/broken_format.rs:36:20
|
||||
|
|
||||
LL | fn check_2(_: impl ImportantTrait2) {}
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `check_2`
|
||||
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:12:50
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
|
||||
| ^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
warning: positional format arguments are not allowed here
|
||||
--> $DIR/broken_format.rs:12:49
|
||||
|
|
||||
@@ -107,7 +128,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: Test {1}
|
||||
--> $DIR/broken_format.rs:40:13
|
||||
--> $DIR/broken_format.rs:47:13
|
||||
|
|
||||
LL | check_3(());
|
||||
| ------- ^^ the trait `ImportantTrait3` is not implemented for `()`
|
||||
@@ -115,27 +136,27 @@ LL | check_3(());
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/broken_format.rs:15:1
|
||||
--> $DIR/broken_format.rs:17:1
|
||||
|
|
||||
LL | trait ImportantTrait3 {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `check_3`
|
||||
--> $DIR/broken_format.rs:31:20
|
||||
--> $DIR/broken_format.rs:37:20
|
||||
|
|
||||
LL | fn check_3(_: impl ImportantTrait3) {}
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `check_3`
|
||||
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:17:42
|
||||
--> $DIR/broken_format.rs:19:53
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: Test ()
|
||||
--> $DIR/broken_format.rs:42:13
|
||||
--> $DIR/broken_format.rs:49:13
|
||||
|
|
||||
LL | check_4(());
|
||||
| ------- ^^ the trait `ImportantTrait4` is not implemented for `()`
|
||||
@@ -143,34 +164,27 @@ LL | check_4(());
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/broken_format.rs:20:1
|
||||
--> $DIR/broken_format.rs:22:1
|
||||
|
|
||||
LL | trait ImportantTrait4 {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `check_4`
|
||||
--> $DIR/broken_format.rs:32:20
|
||||
--> $DIR/broken_format.rs:38:20
|
||||
|
|
||||
LL | fn check_4(_: impl ImportantTrait4) {}
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `check_4`
|
||||
|
||||
warning: expected `}`, found `!`
|
||||
--> $DIR/broken_format.rs:22:42
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:24:53
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| ^^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
warning: unmatched `}` found
|
||||
--> $DIR/broken_format.rs:22:42
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: Test {Self:!}
|
||||
--> $DIR/broken_format.rs:44:13
|
||||
error[E0277]: Test ()
|
||||
--> $DIR/broken_format.rs:51:13
|
||||
|
|
||||
LL | check_5(());
|
||||
| ------- ^^ the trait `ImportantTrait5` is not implemented for `()`
|
||||
@@ -183,11 +197,39 @@ help: this trait has no implementations, consider adding one
|
||||
LL | trait ImportantTrait5 {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `check_5`
|
||||
--> $DIR/broken_format.rs:33:20
|
||||
--> $DIR/broken_format.rs:39:20
|
||||
|
|
||||
LL | fn check_5(_: impl ImportantTrait5) {}
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `check_5`
|
||||
|
||||
error: aborting due to 5 previous errors; 12 warnings emitted
|
||||
warning: invalid format specifier
|
||||
--> $DIR/broken_format.rs:29:53
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")]
|
||||
| ^
|
||||
|
|
||||
= help: no format specifier are supported in this position
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: Test ()
|
||||
--> $DIR/broken_format.rs:53:13
|
||||
|
|
||||
LL | check_6(());
|
||||
| ------- ^^ the trait `ImportantTrait6` is not implemented for `()`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/broken_format.rs:32:1
|
||||
|
|
||||
LL | trait ImportantTrait6 {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `check_6`
|
||||
--> $DIR/broken_format.rs:40:20
|
||||
|
|
||||
LL | fn check_6(_: impl ImportantTrait6) {}
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `check_6`
|
||||
|
||||
error: aborting due to 6 previous errors; 14 warnings emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// check that `pattern_complexity_limit` is feature-gated
|
||||
|
||||
#![pattern_complexity_limit = "42"]
|
||||
//~^ ERROR: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests
|
||||
//~^ ERROR: use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
error[E0658]: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests and will never be stable
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/feature-gate-pattern-complexity-limit.rs:3:1
|
||||
|
|
||||
LL | #![pattern_complexity_limit = "42"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable
|
||||
= note: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
// Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate.
|
||||
|
||||
#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
|
||||
#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable
|
||||
|
||||
#[rustc_variance]
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library
|
||||
//~| NOTE the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized
|
||||
fn main() {}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/feature-gate-rustc-attrs-1.rs:3:1
|
||||
|
|
||||
LL | #[rustc_variance]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable
|
||||
= note: the `#[rustc_variance]` attribute is used for rustc unit tests
|
||||
|
||||
error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable
|
||||
(note that the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized)
|
||||
--> $DIR/feature-gate-rustc-attrs-1.rs:4:1
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/feature-gate-rustc-attrs-1.rs:7:1
|
||||
|
|
||||
LL | #[rustc_nonnull_optimization_guaranteed]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable
|
||||
= note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library
|
||||
= note: the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
||||
@@ -8,15 +8,19 @@ mod unknown { pub macro rustc() {} }
|
||||
#[rustc::unknown]
|
||||
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
||||
//~| ERROR expected attribute, found macro `rustc::unknown`
|
||||
//~| NOTE not an attribute
|
||||
fn f() {}
|
||||
|
||||
#[unknown::rustc]
|
||||
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
||||
//~| ERROR expected attribute, found macro `unknown::rustc`
|
||||
//~| NOTE not an attribute
|
||||
fn g() {}
|
||||
|
||||
#[rustc_dummy]
|
||||
//~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE the `#[rustc_dummy]` attribute is used for rustc unit tests
|
||||
#[rustc_unknown]
|
||||
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
||||
//~| ERROR cannot find attribute `rustc_unknown` in this scope
|
||||
|
||||
@@ -11,37 +11,38 @@ LL | #[rustc::unknown]
|
||||
| ^^^^^^^^^^^^^^ not an attribute
|
||||
|
||||
error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:13:12
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:14:12
|
||||
|
|
||||
LL | #[unknown::rustc]
|
||||
| ^^^^^
|
||||
|
||||
error: expected attribute, found macro `unknown::rustc`
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:13:3
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:14:3
|
||||
|
|
||||
LL | #[unknown::rustc]
|
||||
| ^^^^^^^^^^^^^^ not an attribute
|
||||
|
||||
error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:20:3
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:24:3
|
||||
|
|
||||
LL | #[rustc_unknown]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: cannot find attribute `rustc_unknown` in this scope
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:20:3
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:24:3
|
||||
|
|
||||
LL | #[rustc_unknown]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests and will never be stable
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:18:1
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/feature-gate-rustc-attrs.rs:20:1
|
||||
|
|
||||
LL | #[rustc_dummy]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
|
||||
= note: the `#[rustc_dummy]` attribute is used for rustc unit tests
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
|
||||
#![macro_export]
|
||||
//~^ ERROR: `macro_export` attribute cannot be used at crate level
|
||||
#![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify
|
||||
#![rustc_main]
|
||||
//~^ ERROR: `rustc_main` attribute cannot be used at crate level
|
||||
//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
//~| ERROR: use of an internal attribute [E0658]
|
||||
//~| NOTE: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE: the `#[rustc_main]` attribute is used internally to specify test entry point function
|
||||
#![repr()]
|
||||
//~^ ERROR: `repr` attribute cannot be used at crate level
|
||||
#![path = "3800"]
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
error[E0658]: the `#[rustc_main]` attribute is used internally to specify test entry point function
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1
|
||||
|
|
||||
LL | #![rustc_main]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
|
||||
= note: the `#[rustc_main]` attribute is used internally to specify test entry point function
|
||||
|
||||
error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
|
||||
|
|
||||
LL | #[inline = "2100"] fn f() { }
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@@ -18,7 +19,7 @@ LL | #[inline = "2100"] fn f() { }
|
||||
= note: `#[deny(ill_formed_attribute_input)]` on by default
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
@@ -29,7 +30,7 @@ LL | | }
|
||||
| |_- not a function or closure
|
||||
|
||||
error: attribute should be applied to an `extern crate` item
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:1
|
||||
|
|
||||
LL | #[no_link]
|
||||
| ^^^^^^^^^^
|
||||
@@ -43,7 +44,7 @@ LL | | }
|
||||
| |_- not an `extern crate` item
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1
|
||||
|
|
||||
LL | #[export_name = "2200"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -57,7 +58,7 @@ LL | | }
|
||||
| |_- not a free function, impl method or static
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:8
|
||||
|
|
||||
LL | #[repr(C)]
|
||||
| ^
|
||||
@@ -70,7 +71,7 @@ LL | | }
|
||||
| |_- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:8
|
||||
|
|
||||
LL | #[repr(Rust)]
|
||||
| ^^^^
|
||||
@@ -83,19 +84,19 @@ LL | | }
|
||||
| |_- not a struct, enum, or union
|
||||
|
||||
error: attribute should be applied to an `extern crate` item
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
|
||||
|
|
||||
LL | #![no_link]
|
||||
| ^^^^^^^^^^^ not an `extern crate` item
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
|
||||
|
|
||||
LL | #![export_name = "2200"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
|
||||
|
|
||||
LL | #![inline]
|
||||
| ^^^^^^^^^^ not a function or closure
|
||||
@@ -131,7 +132,7 @@ LL + #[rustc_main]
|
||||
|
|
||||
|
||||
error: `path` attribute cannot be used at crate level
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
|
||||
|
|
||||
LL | #![path = "3800"]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
@@ -146,7 +147,7 @@ LL + #[path = "3800"]
|
||||
|
|
||||
|
||||
error: `automatically_derived` attribute cannot be used at crate level
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1
|
||||
|
|
||||
LL | #![automatically_derived]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -161,7 +162,7 @@ LL + #[automatically_derived]
|
||||
|
|
||||
|
||||
error: `repr` attribute cannot be used at crate level
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
|
||||
|
|
||||
LL | #![repr()]
|
||||
| ^^^^^^^^^^
|
||||
@@ -176,139 +177,139 @@ LL + #[repr()]
|
||||
|
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17
|
||||
|
|
||||
LL | mod inner { #![inline] }
|
||||
| ------------^^^^^^^^^^-- not a function or closure
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5
|
||||
|
|
||||
LL | #[inline] struct S;
|
||||
| ^^^^^^^^^ --------- not a function or closure
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:5
|
||||
|
|
||||
LL | #[inline] type T = S;
|
||||
| ^^^^^^^^^ ----------- not a function or closure
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:5
|
||||
|
|
||||
LL | #[inline] impl S { }
|
||||
| ^^^^^^^^^ ---------- not a function or closure
|
||||
|
||||
error: attribute should be applied to an `extern crate` item
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:17
|
||||
|
|
||||
LL | mod inner { #![no_link] }
|
||||
| ------------^^^^^^^^^^^-- not an `extern crate` item
|
||||
|
||||
error: attribute should be applied to an `extern crate` item
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:74:5
|
||||
|
|
||||
LL | #[no_link] fn f() { }
|
||||
| ^^^^^^^^^^ ---------- not an `extern crate` item
|
||||
|
||||
error: attribute should be applied to an `extern crate` item
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5
|
||||
|
|
||||
LL | #[no_link] struct S;
|
||||
| ^^^^^^^^^^ --------- not an `extern crate` item
|
||||
|
||||
error: attribute should be applied to an `extern crate` item
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5
|
||||
|
|
||||
LL | #[no_link]type T = S;
|
||||
| ^^^^^^^^^^----------- not an `extern crate` item
|
||||
|
||||
error: attribute should be applied to an `extern crate` item
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5
|
||||
|
|
||||
LL | #[no_link] impl S { }
|
||||
| ^^^^^^^^^^ ---------- not an `extern crate` item
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17
|
||||
|
|
||||
LL | mod inner { #![export_name="2200"] }
|
||||
| ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5
|
||||
|
|
||||
LL | #[export_name = "2200"] struct S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5
|
||||
|
|
||||
LL | #[export_name = "2200"] type T = S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5
|
||||
|
|
||||
LL | #[export_name = "2200"] impl S { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:9
|
||||
|
|
||||
LL | #[export_name = "2200"] fn foo();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
|
||||
|
||||
error: attribute should be applied to a free function, impl method or static
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:9
|
||||
|
|
||||
LL | #[export_name = "2200"] fn bar() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:25
|
||||
|
|
||||
LL | mod inner { #![repr(C)] }
|
||||
| --------------------^---- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:12
|
||||
|
|
||||
LL | #[repr(C)] fn f() { }
|
||||
| ^ ---------- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12
|
||||
|
|
||||
LL | #[repr(C)] type T = S;
|
||||
| ^ ----------- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12
|
||||
|
|
||||
LL | #[repr(C)] impl S { }
|
||||
| ^ ---------- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:153:25
|
||||
|
|
||||
LL | mod inner { #![repr(Rust)] }
|
||||
| --------------------^^^^---- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:157:12
|
||||
|
|
||||
LL | #[repr(Rust)] fn f() { }
|
||||
| ^^^^ ---------- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:163:12
|
||||
|
|
||||
LL | #[repr(Rust)] type T = S;
|
||||
| ^^^^ ----------- not a struct, enum, or union
|
||||
|
||||
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:167:12
|
||||
|
|
||||
LL | #[repr(Rust)] impl S { }
|
||||
| ^^^^ ---------- not a struct, enum, or union
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[rustc_force_inline]
|
||||
//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined
|
||||
pub fn bare() {
|
||||
}
|
||||
|
||||
#[rustc_force_inline = "the test requires it"]
|
||||
//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined
|
||||
pub fn justified() {
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
error[E0658]: #[rustc_force_inline] forces a free function to be inlined
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/gate.rs:4:1
|
||||
|
|
||||
LL | #[rustc_force_inline]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
|
||||
= note: `#[rustc_force_inline]` forces a free function to be inlined
|
||||
|
||||
error[E0658]: #[rustc_force_inline] forces a free function to be inlined
|
||||
--> $DIR/gate.rs:9:1
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/gate.rs:11:1
|
||||
|
|
||||
LL | #[rustc_force_inline = "the test requires it"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
|
||||
= note: `#[rustc_force_inline]` forces a free function to be inlined
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate.
|
||||
|
||||
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
||||
//~^ ERROR this is an internal attribute that will never be stable
|
||||
trait Foo<Bar>
|
||||
{}
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute
|
||||
trait Foo<Bar> {}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
error[E0658]: this is an internal attribute that will never be stable
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/feature-gate-on-unimplemented.rs:3:1
|
||||
|
|
||||
LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable
|
||||
= note: see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#[rustc_doc_primitive = "usize"]
|
||||
//~^ ERROR `rustc_doc_primitive` is a rustc internal attribute
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types
|
||||
/// Some docs
|
||||
mod usize {}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
error[E0658]: `rustc_doc_primitive` is a rustc internal attribute
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/feature-gate-doc_primitive.rs:1:1
|
||||
|
|
||||
LL | #[rustc_doc_primitive = "usize"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable
|
||||
= note: the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#[rustc_diagnostic_item = "foomp"] //~ ERROR compiler internal support for linting
|
||||
#[rustc_diagnostic_item = "foomp"]
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes
|
||||
struct Foomp;
|
||||
fn main() {}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
error[E0658]: diagnostic items compiler internal support for linting
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/diagnostic_item.rs:1:1
|
||||
|
|
||||
LL | #[rustc_diagnostic_item = "foomp"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#[rustc_must_implement_one_of(eq, neq)]
|
||||
//~^ ERROR the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
|
||||
//~^ ERROR use of an internal attribute [E0658]
|
||||
//~| NOTE the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable
|
||||
//~| NOTE the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization
|
||||
trait Equal {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
!self.neq(other)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
error[E0658]: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
|
||||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/rustc_must_implement_one_of_gated.rs:1:1
|
||||
|
|
||||
LL | #[rustc_must_implement_one_of(eq, neq)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable
|
||||
= note: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
Reference in New Issue
Block a user