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:
bors
2025-06-13 05:09:09 +00:00
49 changed files with 907 additions and 594 deletions

View File

@@ -36,6 +36,16 @@ macro_rules! gate_alt {
feature_err(&$visitor.sess, $name, $span, $explain).emit(); 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. /// 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)); let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check feature gates for built-in attributes. // Check feature gates for built-in attributes.
if let Some(BuiltinAttribute { if let Some(BuiltinAttribute {
gate: AttributeGate::Gated(_, name, descr, has_feature), gate: AttributeGate::Gated { feature, message, check, notes, .. },
.. ..
}) = attr_info }) = 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. // Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) { if attr.has_name(sym::doc) {

View File

@@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::{Symbol, sym}; use rustc_span::{Symbol, sym};
use crate::{Features, Stability}; use crate::Features;
type GateFn = fn(&Features) -> bool; type GateFn = fn(&Features) -> bool;
@@ -94,34 +94,23 @@ pub enum AttributeSafety {
Unsafe { unsafe_since: Option<Edition> }, Unsafe { unsafe_since: Option<Edition> },
} }
#[derive(Clone, Copy)] #[derive(Clone, Debug, Copy)]
pub enum AttributeGate { pub enum AttributeGate {
/// Is gated by a given feature gate, reason /// A gated attribute which requires a feature gate to be enabled.
/// and function to check if enabled Gated {
Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), /// 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 attribute, can be used on all release channels
Ungated, 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. /// A template that the attribute input must match.
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
@@ -247,7 +236,7 @@ macro_rules! ungated {
} }
macro_rules! gated { 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 { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
@@ -255,10 +244,15 @@ macro_rules! gated {
safety: AttributeSafety::Unsafe { unsafe_since: None }, safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl, template: $tpl,
duplicates: $duplicates, 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 { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
@@ -266,10 +260,15 @@ macro_rules! gated {
safety: AttributeSafety::Unsafe { unsafe_since: None }, safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl, template: $tpl,
duplicates: $duplicates, 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 { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
@@ -277,10 +276,15 @@ macro_rules! gated {
safety: AttributeSafety::Normal, safety: AttributeSafety::Normal,
template: $tpl, template: $tpl,
duplicates: $duplicates, 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 { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
@@ -288,7 +292,12 @@ macro_rules! gated {
safety: AttributeSafety::Normal, safety: AttributeSafety::Normal,
template: $tpl, template: $tpl,
duplicates: $duplicates, 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!( concat!(
"the `#[", "the `#[",
stringify!($attr), stringify!($attr),
"]` attribute is just used for rustc unit tests \ "]` attribute is used for rustc unit tests"
and will never be stable",
), ),
) )
}; };
($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 { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
@@ -317,7 +325,17 @@ macro_rules! rustc_attr {
safety: AttributeSafety::Normal, safety: AttributeSafety::Normal,
template: $tpl, template: $tpl,
duplicates: $duplicates, 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)] #[derive(PartialEq)]
pub enum EncodeCrossCrate { pub enum EncodeCrossCrate {
Yes, Yes,
@@ -668,7 +683,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!( rustc_attr!(
rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#), rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
ErrorFollowing, EncodeCrossCrate::Yes, 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_attr!(
rustc_pub_transparent, Normal, template!(Word), rustc_pub_transparent, Normal, template!(Word),
@@ -695,7 +710,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ErrorFollowing, ErrorFollowing,
EncodeCrossCrate::No, EncodeCrossCrate::No,
"`rustc_never_type_options` is used to experiment with never type fallback and work on \ "`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_attr!(
rustc_allocator, Normal, template!(Word), WarnFollowing, rustc_allocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL EncodeCrossCrate::No,
), ),
rustc_attr!( rustc_attr!(
rustc_nounwind, Normal, template!(Word), WarnFollowing, rustc_nounwind, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL EncodeCrossCrate::No,
), ),
rustc_attr!( rustc_attr!(
rustc_reallocator, Normal, template!(Word), WarnFollowing, rustc_reallocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL EncodeCrossCrate::No,
), ),
rustc_attr!( rustc_attr!(
rustc_deallocator, Normal, template!(Word), WarnFollowing, rustc_deallocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL EncodeCrossCrate::No,
), ),
rustc_attr!( rustc_attr!(
rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL EncodeCrossCrate::No,
), ),
gated!( gated!(
default_lib_allocator, Normal, template!(Word), WarnFollowing, default_lib_allocator, Normal, template!(Word), WarnFollowing,
@@ -762,7 +777,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
rustc_attr!( rustc_attr!(
rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, 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_attr!(
rustc_builtin_macro, Normal, rustc_builtin_macro, Normal,
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing, template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
EncodeCrossCrate::Yes, IMPL_DETAIL EncodeCrossCrate::Yes,
), ),
rustc_attr!( rustc_attr!(
rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, INTERNAL_UNSTABLE EncodeCrossCrate::No,
), ),
rustc_attr!( rustc_attr!(
rustc_macro_transparency, Normal, rustc_macro_transparency, Normal,
@@ -786,7 +801,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!( rustc_attr!(
rustc_autodiff, Normal, rustc_autodiff, Normal,
template!(Word, List: r#""...""#), DuplicatesOk, template!(Word, List: r#""...""#), DuplicatesOk,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE EncodeCrossCrate::Yes,
), ),
// Traces that are left when `cfg` and `cfg_attr` attributes are expanded. // 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 // 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" NameValueStr: "message"
), ),
ErrorFollowing, EncodeCrossCrate::Yes, ErrorFollowing, EncodeCrossCrate::Yes,
INTERNAL_UNSTABLE "see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
), ),
rustc_attr!( rustc_attr!(
rustc_confusables, Normal, rustc_confusables, Normal,
template!(List: r#""name1", "name2", ..."#), template!(List: r#""name1", "name2", ..."#),
ErrorFollowing, EncodeCrossCrate::Yes, ErrorFollowing, EncodeCrossCrate::Yes,
INTERNAL_UNSTABLE,
), ),
// Enumerates "identity-like" conversion methods to suggest on type mismatch. // Enumerates "identity-like" conversion methods to suggest on type mismatch.
rustc_attr!( rustc_attr!(
rustc_conversion_suggestion, Normal, template!(Word), 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 // Prevents field reads in the marked trait or method to be considered
// during dead code analysis. // during dead code analysis.
rustc_attr!( rustc_attr!(
rustc_trivial_field_reads, Normal, template!(Word), 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 // Used by the `rustc::potential_query_instability` lint to warn methods which
// might not be stable during incremental compilation. // might not be stable during incremental compilation.
rustc_attr!( rustc_attr!(
rustc_lint_query_instability, Normal, template!(Word), 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 // Used by the `rustc::untracked_query_information` lint to warn methods which
// might not be stable during incremental compilation. // might not be stable during incremental compilation.
rustc_attr!( rustc_attr!(
rustc_lint_untracked_query_information, Normal, template!(Word), 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 // 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. // APIs. Any function with this attribute will be checked by that lint.
rustc_attr!( rustc_attr!(
rustc_lint_diagnostics, Normal, template!(Word), 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` // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
// types (as well as any others in future). // types (as well as any others in future).
rustc_attr!( rustc_attr!(
rustc_lint_opt_ty, Normal, template!(Word), 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 // Used by the `rustc::bad_opt_access` lint on fields
// types (as well as any others in future). // types (as well as any others in future).
rustc_attr!( rustc_attr!(
rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), 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_attr!(
rustc_promotable, Normal, template!(Word), WarnFollowing, rustc_promotable, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL), EncodeCrossCrate::No, ),
rustc_attr!( rustc_attr!(
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing, 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. // Do not const-check this function's body. It will always get replaced during CTFE.
rustc_attr!( rustc_attr!(
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, 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_attr!(
rustc_const_panic_str, Normal, template!(Word), WarnFollowing, 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_attr!(
rustc_const_stable_indirect, Normal, 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_attr!(
rustc_intrinsic_const_stable_indirect, Normal, 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!( gated!(
rustc_allow_const_fn_unstable, Normal, 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, rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
EncodeCrossCrate::Yes, EncodeCrossCrate::Yes,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ "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_attr!(
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing, rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
EncodeCrossCrate::Yes, EncodeCrossCrate::Yes,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ "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_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes, EncodeCrossCrate::Yes,
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \ "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
guaranteed niche optimizations in libcore and libstd and will never be stable\n\ guaranteed niche optimizations in the standard library",
(note that the compiler does not even check whether the type indeed is being non-null-optimized; \ "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)", 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_attr!(
rustc_as_ptr, Normal, template!(Word), ErrorFollowing, rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes, 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_attr!(
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes, 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_attr!(
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing, rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes, 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_attr!(
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
@@ -950,15 +966,15 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
rustc_attr!( rustc_attr!(
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, 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_attr!(
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, 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_attr!(
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, 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_attr!(
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
@@ -970,7 +986,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(Word), template!(Word),
ErrorFollowing, ErrorFollowing,
EncodeCrossCrate::No, 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_attr!(
rustc_do_not_implement_via_object, rustc_do_not_implement_via_object,
@@ -978,14 +994,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(Word), template!(Word),
ErrorFollowing, ErrorFollowing,
EncodeCrossCrate::No, 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`)" (`impl Trait for dyn Trait`)"
), ),
rustc_attr!( rustc_attr!(
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes, ErrorFollowing, EncodeCrossCrate::Yes,
"#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ "`#[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]." the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`."
), ),
BuiltinAttribute { BuiltinAttribute {
@@ -996,12 +1012,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
safety: AttributeSafety::Normal, safety: AttributeSafety::Normal,
template: template!(NameValueStr: "name"), template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing, duplicates: ErrorFollowing,
gate: Gated( gate: Gated{
Stability::Unstable, feature: sym::rustc_attrs,
sym::rustc_attrs, message: "use of an internal attribute",
"diagnostic items compiler internal support for linting", check: Features::rustc_attrs,
Features::rustc_attrs, notes: &["the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types \
), from the standard library for diagnostic purposes"],
},
}, },
gated!( gated!(
// Used in resolve: // Used in resolve:
@@ -1015,14 +1032,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!( rustc_attr!(
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
overflow checking behavior of several libcore functions that are inlined \ overflow checking behavior of several functions in the standard library that are inlined \
across crates and will never be stable", across crates",
), ),
rustc_attr!( rustc_attr!(
rustc_reservation_impl, Normal, rustc_reservation_impl, Normal,
template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes, template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
"the `#[rustc_reservation_impl]` attribute is internally used \ "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_attr!(
rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing, 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, ..."), rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
ErrorFollowing, EncodeCrossCrate::No, ErrorFollowing, EncodeCrossCrate::No,
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \ "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 \ definition of a trait. Its syntax and semantics are highly experimental and will be \
being exposed outside of the std" subject to change before stabilization",
), ),
rustc_attr!( rustc_attr!(
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing, 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!( gated!(
rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
@@ -1066,11 +1084,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
rustc_attr!( rustc_attr!(
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, 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_attr!(
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, 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 { pub fn is_builtin_attr_name(name: Symbol) -> bool {
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
} }

View File

@@ -40,14 +40,6 @@ pub struct Feature {
issue: Option<NonZero<u32>>, 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)] #[derive(Clone, Copy, Debug, Hash)]
pub enum UnstableFeatures { pub enum UnstableFeatures {
/// Disallow use of unstable features, as on beta/stable channels. /// 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 accepted::ACCEPTED_LANG_FEATURES;
pub use builtin_attrs::{ pub use builtin_attrs::{
AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType, AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes, BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate,
encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr,
is_valid_for_get_attr,
}; };
pub use removed::REMOVED_LANG_FEATURES; pub use removed::REMOVED_LANG_FEATURES;
pub use unstable::{ pub use unstable::{

View File

@@ -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_fn = declaration of an `unsafe` function
lint_builtin_decl_unsafe_method = declaration of an `unsafe` method 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 lint_builtin_deref_nullptr = dereferencing a null pointer
.label = this code causes undefined behavior when executed .label = this code causes undefined behavior when executed

View File

@@ -22,7 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind};
use rustc_ast::{self as ast, *}; use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust::expr_to_string; use rustc_ast_pretty::pprust::expr_to_string;
use rustc_errors::{Applicability, LintDiagnostic}; 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 as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; 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::errors::BuiltinEllipsisInclusiveRangePatterns;
use crate::lints::{ use crate::lints::{
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDerefNullptr, BuiltinDoubleNegations,
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, 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]) { fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
use rustc_ast::token::CommentKind; use rustc_ast::token::CommentKind;

View File

@@ -174,7 +174,6 @@ early_lint_methods!(
AnonymousParameters: AnonymousParameters, AnonymousParameters: AnonymousParameters,
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
NonCamelCaseTypes: NonCamelCaseTypes, NonCamelCaseTypes: NonCamelCaseTypes,
DeprecatedAttr: DeprecatedAttr::default(),
WhileTrue: WhileTrue, WhileTrue: WhileTrue,
NonAsciiIdents: NonAsciiIdents, NonAsciiIdents: NonAsciiIdents,
IncompleteInternalFeatures: IncompleteInternalFeatures, IncompleteInternalFeatures: IncompleteInternalFeatures,

View File

@@ -199,32 +199,6 @@ pub(crate) struct BuiltinAnonymousParams<'a> {
pub ty_snip: &'a str, 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)] #[derive(LintDiagnostic)]
#[diag(lint_builtin_unused_doc_comment)] #[diag(lint_builtin_unused_doc_comment)]
pub(crate) struct BuiltinUnusedDocComment<'a> { pub(crate) struct BuiltinUnusedDocComment<'a> {

View File

@@ -29,58 +29,45 @@ pub enum ParseMode {
Format, Format,
/// An inline assembly template string for `asm!`. /// An inline assembly template string for `asm!`.
InlineAsm, 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 /// 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. /// to emit. These are emitted as a stream by the `Parser` class.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Piece<'a> { pub enum Piece<'input> {
/// A literal string which should directly be emitted /// A literal string which should directly be emitted
Lit(&'a str), Lit(&'input str),
/// This describes that formatting should process the next argument (as /// This describes that formatting should process the next argument (as
/// specified inside) for emission. /// specified inside) for emission.
NextArgument(Box<Argument<'a>>), NextArgument(Box<Argument<'input>>),
} }
/// Representation of an argument specification. /// Representation of an argument specification.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Argument<'a> { pub struct Argument<'input> {
/// Where to find this argument /// Where to find this argument
pub position: Position<'a>, pub position: Position<'input>,
/// The span of the position indicator. Includes any whitespace in implicit /// The span of the position indicator. Includes any whitespace in implicit
/// positions (`{ }`). /// positions (`{ }`).
pub position_span: Range<usize>, pub position_span: Range<usize>,
/// How to format the argument /// 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 { pub fn is_identifier(&self) -> bool {
matches!(self.position, Position::ArgumentNamed(_)) matches!(self.position, Position::ArgumentNamed(_)) && self.format == FormatSpec::default()
&& 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,
},
)
} }
} }
/// Specification for the formatting of an argument in the format string. /// Specification for the formatting of an argument in the format string.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Default)]
pub struct FormatSpec<'a> { pub struct FormatSpec<'input> {
/// Optionally specified character to fill alignment with. /// Optionally specified character to fill alignment with.
pub fill: Option<char>, pub fill: Option<char>,
/// Span of the optionally specified fill character. /// Span of the optionally specified fill character.
@@ -96,30 +83,30 @@ pub struct FormatSpec<'a> {
/// The `x` or `X` flag. (Only for `Debug`.) /// The `x` or `X` flag. (Only for `Debug`.)
pub debug_hex: Option<DebugHex>, pub debug_hex: Option<DebugHex>,
/// The integer precision to use. /// The integer precision to use.
pub precision: Count<'a>, pub precision: Count<'input>,
/// The span of the precision formatting flag (for diagnostics). /// The span of the precision formatting flag (for diagnostics).
pub precision_span: Option<Range<usize>>, pub precision_span: Option<Range<usize>>,
/// The string width requested for the resulting format. /// 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). /// The span of the width formatting flag (for diagnostics).
pub width_span: Option<Range<usize>>, pub width_span: Option<Range<usize>>,
/// The descriptor string representing the name of the format desired for /// The descriptor string representing the name of the format desired for
/// this argument, this can be empty or any number of characters, although /// this argument, this can be empty or any number of characters, although
/// it is required to be one word. /// it is required to be one word.
pub ty: &'a str, pub ty: &'input str,
/// The span of the descriptor string (for diagnostics). /// The span of the descriptor string (for diagnostics).
pub ty_span: Option<Range<usize>>, pub ty_span: Option<Range<usize>>,
} }
/// Enum describing where an argument for a format can be located. /// Enum describing where an argument for a format can be located.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Position<'a> { pub enum Position<'input> {
/// The argument is implied to be located at an index /// The argument is implied to be located at an index
ArgumentImplicitlyIs(usize), ArgumentImplicitlyIs(usize),
/// The argument is located at a specific index given in the format, /// The argument is located at a specific index given in the format,
ArgumentIs(usize), ArgumentIs(usize),
/// The argument has a name. /// The argument has a name.
ArgumentNamed(&'a str), ArgumentNamed(&'input str),
} }
impl Position<'_> { impl Position<'_> {
@@ -132,7 +119,7 @@ impl Position<'_> {
} }
/// Enum of alignments which are supported. /// Enum of alignments which are supported.
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq, Default)]
pub enum Alignment { pub enum Alignment {
/// The value will be aligned to the left. /// The value will be aligned to the left.
AlignLeft, AlignLeft,
@@ -141,6 +128,7 @@ pub enum Alignment {
/// The value will be aligned in the center. /// The value will be aligned in the center.
AlignCenter, AlignCenter,
/// The value will take on a default alignment. /// The value will take on a default alignment.
#[default]
AlignUnknown, AlignUnknown,
} }
@@ -164,17 +152,18 @@ pub enum DebugHex {
/// A count is used for the precision and width parameters of an integer, and /// A count is used for the precision and width parameters of an integer, and
/// can reference either an argument or a literal integer. /// can reference either an argument or a literal integer.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Default)]
pub enum Count<'a> { pub enum Count<'input> {
/// The count is specified explicitly. /// The count is specified explicitly.
CountIs(u16), CountIs(u16),
/// The count is specified by the argument with the given name. /// 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. /// The count is specified by the argument at the given index.
CountIsParam(usize), CountIsParam(usize),
/// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index. /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
CountIsStar(usize), CountIsStar(usize),
/// The count is implied and cannot be explicitly specified. /// The count is implied and cannot be explicitly specified.
#[default]
CountImplied, CountImplied,
} }
@@ -208,10 +197,10 @@ pub enum Suggestion {
/// ///
/// This is a recursive-descent parser for the sake of simplicity, and if /// This is a recursive-descent parser for the sake of simplicity, and if
/// necessary there's probably lots of room for improvement performance-wise. /// necessary there's probably lots of room for improvement performance-wise.
pub struct Parser<'a> { pub struct Parser<'input> {
mode: ParseMode, mode: ParseMode,
/// Input to be parsed /// 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 /// 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)>, input_vec: Vec<(Range<usize>, usize, char)>,
/// Index into input_vec /// Index into input_vec
@@ -237,15 +226,15 @@ pub struct Parser<'a> {
pub line_spans: Vec<Range<usize>>, pub line_spans: Vec<Range<usize>>,
} }
impl<'a> Iterator for Parser<'a> { impl<'input> Iterator for Parser<'input> {
type Item = Piece<'a>; type Item = Piece<'input>;
fn next(&mut self) -> Option<Piece<'a>> { fn next(&mut self) -> Option<Piece<'input>> {
if let Some(&(Range { start, end }, idx, ch)) = self.input_vec.get(self.input_vec_index) { if let Some((Range { start, end }, idx, ch)) = self.peek() {
match ch { match ch {
'{' => { '{' => {
self.input_vec_index += 1; 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; self.input_vec_index += 1;
// double open brace escape: "{{" // double open brace escape: "{{"
// next state after this is either end-of-input or seen-a-brace // 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 // single open brace
self.last_open_brace = Some(start..end); self.last_open_brace = Some(start..end);
let arg = self.argument(); 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 { if self.is_source_literal {
self.arg_places.push(start..close_brace_range.end); self.arg_places.push(start..close_brace_range.end);
} }
} else if let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { } else {
match c { self.missing_closing_brace(&arg);
'?' => self.suggest_format_debug(),
'<' | '^' | '>' => self.suggest_format_align(c),
_ => {
self.suggest_positional_arg_instead_of_captured_arg(arg.clone())
}
}
} }
Some(Piece::NextArgument(Box::new(arg))) Some(Piece::NextArgument(Box::new(arg)))
} }
} }
'}' => { '}' => {
self.input_vec_index += 1; 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; self.input_vec_index += 1;
// double close brace escape: "}}" // double close brace escape: "}}"
// next state after this is either end-of-input or start // 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 /// Creates a new parser for the given unescaped input string and
/// optional code snippet (the input as written before being unescaped), /// 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. /// 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, /// If the input comes via `println` or `panic`, then it has a newline already appended,
/// which is reflected in the `appended_newline` parameter. /// which is reflected in the `appended_newline` parameter.
pub fn new( pub fn new(
input: &'a str, input: &'input str,
style: Option<usize>, style: Option<usize>,
snippet: Option<String>, snippet: Option<String>,
appended_newline: bool, 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 /// Optionally consumes the specified character. If the character is not at
/// the current position, then the current iterator isn't moved and `false` is /// the current position, then the current iterator isn't moved and `false` is
/// returned, otherwise the character is consumed and `true` is returned. /// 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, otherwise the character is consumed and the current position is
/// returned. /// returned.
fn consume_pos(&mut self, ch: char) -> Option<(Range<usize>, usize)> { 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 let Some((r, i, c)) = self.peek()
if ch == *c { && ch == c
self.input_vec_index += 1; {
return Some((r.clone(), *i)); self.input_vec_index += 1;
} return Some((r, i));
} }
None None
} }
/// Forces consumption of the specified character. If the character is not /// Called if a closing brace was not found.
/// found, an error is emitted. fn missing_closing_brace(&mut self, arg: &Argument<'_>) {
fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option<Range<usize>> { let (range, description) = if let Some((r, _, c)) = self.peek() {
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()?
(r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug())) (r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug()))
} else { } else {
( (
@@ -471,7 +458,13 @@ impl<'a> Parser<'a> {
suggestion: Suggestion::None, 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 /// 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 /// Parses all of a string which is to be considered a "raw literal" in a
/// format string. This is everything outside of the braces. /// format string. This is everything outside of the braces.
fn string(&mut self, start: usize) -> &'a str { fn string(&mut self, start: usize) -> &'input str {
while let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { while let Some((r, i, c)) = self.peek() {
match c { match c {
'{' | '}' => { '{' | '}' => {
return &self.input[start..*i]; return &self.input[start..i];
} }
'\n' if self.is_source_literal => { '\n' if self.is_source_literal => {
self.input_vec_index += 1; 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. /// 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 start_idx = self.input_vec_index;
let position = self.position(); let position = self.position();
@@ -518,6 +511,7 @@ impl<'a> Parser<'a> {
let format = match self.mode { let format = match self.mode {
ParseMode::Format => self.format(), ParseMode::Format => self.format(),
ParseMode::InlineAsm => self.inline_asm(), ParseMode::InlineAsm => self.inline_asm(),
ParseMode::Diagnostic => self.diagnostic(),
}; };
// Resolve position after parsing format spec. // Resolve position after parsing format spec.
@@ -536,31 +530,27 @@ impl<'a> Parser<'a> {
/// integer index of an argument, a named argument, or a blank string. /// integer index of an argument, a named argument, or a blank string.
/// Returns `Some(parsed_position)` if the position is not implicitly /// Returns `Some(parsed_position)` if the position is not implicitly
/// consuming a macro argument, `None` if it's the case. /// 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() { if let Some(i) = self.integer() {
Some(ArgumentIs(i.into())) Some(ArgumentIs(i.into()))
} else { } else {
match self.input_vec.get(self.input_vec_index) { match self.peek() {
Some((range, _, c)) if rustc_lexer::is_id_start(*c) => { Some((range, _, c)) if rustc_lexer::is_id_start(c) => {
let start = range.start; let start = range.start;
let word = self.word(); let word = self.word();
// Recover from `r#ident` in format strings. // Recover from `r#ident` in format strings.
// FIXME: use a let chain if word == "r"
if word == "r" { && let Some((r, _, '#')) = self.peek()
if let Some((r, _, '#')) = self.input_vec.get(self.input_vec_index) { && self.peek_ahead().is_some_and(|(_, _, c)| rustc_lexer::is_id_start(c))
if self {
.input_vec self.input_vec_index += 1;
.get(self.input_vec_index + 1) let prefix_end = r.end;
.is_some_and(|(_, _, c)| rustc_lexer::is_id_start(*c)) let word = self.word();
{ let prefix_span = start..prefix_end;
self.input_vec_index += 1; let full_span =
let prefix_end = r.end; start..self.input_vec_index2range(self.input_vec_index).start;
let word = self.word(); self.errors.insert(0, ParseError {
let prefix_span = start..prefix_end;
let full_span =
start..self.input_vec_index2range(self.input_vec_index).start;
self.errors.insert(0, ParseError {
description: "raw identifiers are not supported".to_owned(), description: "raw identifiers are not supported".to_owned(),
note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()), note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()),
label: "raw identifier used here".to_owned(), label: "raw identifier used here".to_owned(),
@@ -568,9 +558,7 @@ impl<'a> Parser<'a> {
secondary_label: None, secondary_label: None,
suggestion: Suggestion::RemoveRawIdent(prefix_span), suggestion: Suggestion::RemoveRawIdent(prefix_span),
}); });
return Some(ArgumentNamed(word)); return Some(ArgumentNamed(word));
}
}
} }
Some(ArgumentNamed(word)) Some(ArgumentNamed(word))
@@ -584,7 +572,7 @@ impl<'a> Parser<'a> {
} }
fn input_vec_index2pos(&self, index: usize) -> usize { 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> { 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 /// Parses a format specifier at the current position, returning all of the
/// relevant information in the `FormatSpec` struct. /// relevant information in the `FormatSpec` struct.
fn format(&mut self) -> FormatSpec<'a> { fn format(&mut self) -> FormatSpec<'input> {
let mut spec = FormatSpec { let mut spec = FormatSpec::default();
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,
};
if !self.consume(':') { if !self.consume(':') {
return spec; return spec;
} }
// fill character // fill character
if let Some(&(ref r, _, c)) = self.input_vec.get(self.input_vec_index) { if let (Some((r, _, c)), Some((_, _, '>' | '<' | '^'))) = (self.peek(), self.peek_ahead()) {
if let Some((_, _, '>' | '<' | '^')) = self.input_vec.get(self.input_vec_index + 1) { self.input_vec_index += 1;
self.input_vec_index += 1; spec.fill = Some(c);
spec.fill = Some(c); spec.fill_span = Some(r);
spec.fill_span = Some(r.clone());
}
} }
// Alignment // Alignment
if self.consume('<') { if self.consume('<') {
@@ -701,24 +674,21 @@ impl<'a> Parser<'a> {
} }
} else if let Some((range, _)) = self.consume_pos('?') { } else if let Some((range, _)) = self.consume_pos('?') {
spec.ty = "?"; spec.ty = "?";
if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) { if let Some((r, _, c @ ('#' | 'x' | 'X'))) = self.peek() {
match c { self.errors.insert(
'#' | 'x' | 'X' => self.errors.insert( 0,
0, ParseError {
ParseError { description: format!("expected `}}`, found `{c}`"),
description: format!("expected `}}`, found `{c}`"), note: None,
note: None, label: "expected `'}'`".into(),
label: "expected `'}'`".into(), span: r.clone(),
span: r.clone(), secondary_label: None,
secondary_label: None, suggestion: Suggestion::ReorderFormatParameter(
suggestion: Suggestion::ReorderFormatParameter( range.start..r.end,
range.start..r.end, format!("{c}?"),
format!("{c}?"), ),
), },
}, );
),
_ => (),
}
} }
} else { } else {
spec.ty = self.word(); 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 /// Parses an inline assembly template modifier at the current position, returning the modifier
/// in the `ty` field of the `FormatSpec` struct. /// in the `ty` field of the `FormatSpec` struct.
fn inline_asm(&mut self) -> FormatSpec<'a> { fn inline_asm(&mut self) -> FormatSpec<'input> {
let mut spec = FormatSpec { let mut spec = FormatSpec::default();
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,
};
if !self.consume(':') { if !self.consume(':') {
return spec; return spec;
} }
@@ -764,10 +721,26 @@ impl<'a> Parser<'a> {
spec 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 /// Parses a `Count` parameter at the current position. This does not check
/// for 'CountIsNextParam' because that is only used in precision, not /// for 'CountIsNextParam' because that is only used in precision, not
/// width. /// width.
fn count(&mut self) -> Count<'a> { fn count(&mut self) -> Count<'input> {
if let Some(i) = self.integer() { if let Some(i) = self.integer() {
if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) }
} else { } else {
@@ -786,10 +759,10 @@ impl<'a> Parser<'a> {
/// Parses a word starting at the current position. A word is the same as 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. /// 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; let index = self.input_vec_index;
match self.input_vec.get(self.input_vec_index) { match self.peek() {
Some(&(ref r, i, c)) if rustc_lexer::is_id_start(c) => { Some((ref r, i, c)) if rustc_lexer::is_id_start(c) => {
self.input_vec_index += 1; self.input_vec_index += 1;
(r.start, i) (r.start, i)
} }
@@ -798,7 +771,7 @@ impl<'a> Parser<'a> {
} }
}; };
let (err_end, end): (usize, usize) = loop { 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) { if rustc_lexer::is_id_continue(c) {
self.input_vec_index += 1; self.input_vec_index += 1;
} else { } else {
@@ -828,7 +801,7 @@ impl<'a> Parser<'a> {
let mut found = false; let mut found = false;
let mut overflow = false; let mut overflow = false;
let start_index = self.input_vec_index; 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) { if let Some(i) = c.to_digit(10) {
self.input_vec_index += 1; self.input_vec_index += 1;
let (tmp, mul_overflow) = cur.overflowing_mul(10); 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 the argument is not an identifier, it is not a field access.
if !arg.is_identifier() { if !arg.is_identifier() {
return; return;

View File

@@ -553,3 +553,45 @@ fn asm_concat() {
assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]); assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]);
assert_eq!(parser.line_spans, &[]); 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());
}

View File

@@ -17,7 +17,7 @@ use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue};
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId; use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol, sym};
use crate::Session; use crate::Session;
use crate::config::{Cfg, CheckCfg}; use crate::config::{Cfg, CheckCfg};
@@ -192,8 +192,11 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
} else { } else {
err.subdiagnostic(FeatureDiagnosticHelp { feature }); err.subdiagnostic(FeatureDiagnosticHelp { feature });
} }
if feature == sym::rustc_attrs {
if sess.opts.unstable_opts.ui_testing { // 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()); err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
} else if let Some(suggestion) = SuggestUpgradeCompiler::new() { } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
err.subdiagnostic(suggestion); err.subdiagnostic(suggestion);

View File

@@ -810,7 +810,8 @@ impl<'tcx> OnUnimplementedFormatString {
let mut result = Ok(()); 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. // 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 // In other words we'd like to let the author know, but we can still try to format the string later
Ok(FormatString { warnings, .. }) => { Ok(FormatString { warnings, .. }) => {
@@ -848,34 +849,27 @@ impl<'tcx> OnUnimplementedFormatString {
} }
} }
} }
// Errors from the underlying `rustc_parse_format::Parser` // Error from the underlying `rustc_parse_format::Parser`
Err(errors) => { Err(e) => {
// we cannot return errors from processing the format string as hard error here // 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 // 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 // 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 // so that users are aware that something is not correct
for e in errors { if self.is_diagnostic_namespace_variant {
if self.is_diagnostic_namespace_variant { if let Some(trait_def_id) = trait_def_id.as_local() {
if let Some(trait_def_id) = trait_def_id.as_local() { tcx.emit_node_span_lint(
tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(trait_def_id),
tcx.local_def_id_to_hir_id(trait_def_id),
self.span,
WrappedParserError { description: e.description, label: e.label },
);
}
} else {
let reported = struct_span_code_err!(
tcx.dcx(),
self.span, self.span,
E0231, WrappedParserError { description: e.description, label: e.label },
"{}", );
e.description,
)
.emit();
result = Err(reported);
} }
} else {
let reported =
struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,)
.emit();
result = Err(reported);
} }
} }
} }
@@ -896,7 +890,8 @@ impl<'tcx> OnUnimplementedFormatString {
Ctx::RustcOnUnimplemented { tcx, trait_def_id } 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) s.format(args)
} else { } else {
// we cannot return errors from processing the format string as hard error here // we cannot return errors from processing the format string as hard error here

View File

@@ -198,7 +198,7 @@ enum LitOrArg {
impl FilterFormatString { impl FilterFormatString {
fn parse(input: Symbol) -> Self { 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 { .map(|p| match p {
Piece::Lit(s) => LitOrArg::Lit(s.to_owned()), Piece::Lit(s) => LitOrArg::Lit(s.to_owned()),
// We just ignore formatspecs here // We just ignore formatspecs here

View File

@@ -5,12 +5,11 @@ use errors::*;
use rustc_middle::ty::print::TraitRefPrintSugared; use rustc_middle::ty::print::TraitRefPrintSugared;
use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
use rustc_parse_format::{ use rustc_parse_format::{
Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
Position,
}; };
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::def_id::DefId; 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", /// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
/// either as string pieces or dynamic arguments. /// either as string pieces or dynamic arguments.
@@ -160,32 +159,32 @@ impl FormatString {
pub fn parse<'tcx>( pub fn parse<'tcx>(
input: Symbol, input: Symbol,
snippet: Option<String>,
span: Span, span: Span,
ctx: &Ctx<'tcx>, ctx: &Ctx<'tcx>,
) -> Result<Self, Vec<ParseError>> { ) -> Result<Self, ParseError> {
let s = input.as_str(); let s = input.as_str();
let mut parser = Parser::new(s, None, None, false, ParseMode::Format); let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic);
let mut pieces = Vec::new(); let pieces: Vec<_> = parser.by_ref().collect();
if let Some(err) = parser.errors.into_iter().next() {
return Err(err);
}
let mut warnings = Vec::new(); let mut warnings = Vec::new();
for piece in &mut parser { let pieces = pieces
match piece { .into_iter()
RpfPiece::Lit(lit) => { .map(|piece| match piece {
pieces.push(Piece::Lit(lit.into())); RpfPiece::Lit(lit) => Piece::Lit(lit.into()),
}
RpfPiece::NextArgument(arg) => { RpfPiece::NextArgument(arg) => {
warn_on_format_spec(arg.format.clone(), &mut warnings, span); warn_on_format_spec(&arg.format, &mut warnings, span, parser.is_source_literal);
let arg = parse_arg(&arg, ctx, &mut warnings, span); let arg = parse_arg(&arg, ctx, &mut warnings, span, parser.is_source_literal);
pieces.push(Piece::Arg(arg)); Piece::Arg(arg)
} }
} })
} .collect();
if parser.errors.is_empty() { Ok(FormatString { input, pieces, span, warnings })
Ok(FormatString { input, pieces, span, warnings })
} else {
Err(parser.errors)
}
} }
pub fn format(&self, args: &FormatArgs<'_>) -> String { pub fn format(&self, args: &FormatArgs<'_>) -> String {
@@ -229,11 +228,12 @@ fn parse_arg<'tcx>(
ctx: &Ctx<'tcx>, ctx: &Ctx<'tcx>,
warnings: &mut Vec<FormatWarning>, warnings: &mut Vec<FormatWarning>,
input_span: Span, input_span: Span,
is_source_literal: bool,
) -> FormatArg { ) -> FormatArg {
let (Ctx::RustcOnUnimplemented { tcx, trait_def_id } let (Ctx::RustcOnUnimplemented { tcx, trait_def_id }
| Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; | 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 { match arg.position {
// Something like "hello {name}" // Something like "hello {name}"
@@ -283,39 +283,24 @@ fn parse_arg<'tcx>(
/// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything /// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything
/// with specifiers, so emit a warning if they are used. /// with specifiers, so emit a warning if they are used.
fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) { fn warn_on_format_spec(
if !matches!( spec: &FormatSpec<'_>,
spec, warnings: &mut Vec<FormatWarning>,
FormatSpec { input_span: Span,
fill: None, is_source_literal: bool,
fill_span: None, ) {
align: Alignment::AlignUnknown, if spec.ty != "" {
sign: None, let span = spec
alternate: false, .ty_span
zero_pad: false, .as_ref()
debug_hex: None, .map(|inner| slice_span(input_span, inner.clone(), is_source_literal))
precision: Count::CountImplied, .unwrap_or(input_span);
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);
warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() }) warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() })
} }
} }
fn slice_span(input: Span, range: Range<usize>) -> Span { fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span {
let span = input.data(); if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input }
Span::new(
span.lo + BytePos::from_usize(range.start),
span.lo + BytePos::from_usize(range.end),
span.ctxt,
span.parent,
)
} }
pub mod errors { pub mod errors {

View File

@@ -1636,6 +1636,19 @@ fn test_chunk_by() {
assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next_back(), Some(&[1][..]));
assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
assert_eq!(iter.next_back(), None); 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] #[test]

View File

@@ -1847,6 +1847,8 @@ mod prim_ref {}
/// - If `T` is guaranteed to be subject to the [null pointer /// - If `T` is guaranteed to be subject to the [null pointer
/// optimization](option/index.html#representation), and `E` is an enum satisfying the following /// 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". /// 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. /// - The enum `E` has exactly two variants.
/// - One variant has exactly one field, of type `T`. /// - One variant has exactly one field, of type `T`.
/// - All fields of the other variant are zero-sized with 1-byte alignment. /// - All fields of the other variant are zero-sized with 1-byte alignment.
@@ -1920,6 +1922,7 @@ mod prim_ref {}
/// [`Pointer`]: fmt::Pointer /// [`Pointer`]: fmt::Pointer
/// [`UnwindSafe`]: panic::UnwindSafe /// [`UnwindSafe`]: panic::UnwindSafe
/// [`RefUnwindSafe`]: panic::RefUnwindSafe /// [`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 /// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
/// these traits are specially known to the compiler. /// these traits are specially known to the compiler.

View File

@@ -3376,6 +3376,13 @@ where
#[stable(feature = "slice_group_by", since = "1.77.0")] #[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 {} 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")] #[stable(feature = "slice_group_by", since = "1.77.0")]
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@@ -891,6 +891,19 @@ impl AtomicBool {
/// Err(false)); /// Err(false));
/// assert_eq!(some_bool.load(Ordering::Relaxed), 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] #[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[doc(alias = "compare_and_swap")] #[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] #[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[doc(alias = "compare_and_swap")] #[doc(alias = "compare_and_swap")]
@@ -1271,11 +1297,14 @@ impl AtomicBool {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. /// critical section or mutex.
/// In particular, this method will not circumvent the [ABA Problem]. ///
/// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -1338,11 +1367,14 @@ impl AtomicBool {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. /// critical section or mutex.
/// In particular, this method will not circumvent the [ABA Problem]. ///
/// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -1393,11 +1425,14 @@ impl AtomicBool {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. /// critical section or mutex.
/// In particular, this method will not circumvent the [ABA Problem]. ///
/// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -1825,6 +1860,20 @@ impl<T> AtomicPtr<T> {
/// let value = some_ptr.compare_exchange(ptr, other_ptr, /// let value = some_ptr.compare_exchange(ptr, other_ptr,
/// Ordering::SeqCst, Ordering::Relaxed); /// 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] #[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "ptr")] #[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] #[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "ptr")] #[cfg(target_has_atomic = "ptr")]
@@ -1917,11 +1980,15 @@ impl<T> AtomicPtr<T> {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. /// critical section or mutex.
/// In particular, this method will not circumvent the [ABA Problem]. ///
/// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -1992,11 +2059,15 @@ impl<T> AtomicPtr<T> {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. /// critical section or mutex.
/// In particular, this method will not circumvent the [ABA Problem]. ///
/// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -2057,11 +2128,15 @@ impl<T> AtomicPtr<T> {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. /// critical section or mutex.
/// In particular, this method will not circumvent the [ABA Problem]. ///
/// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -2967,6 +3042,20 @@ macro_rules! atomic_int {
/// Err(10)); /// Err(10));
/// assert_eq!(some_var.load(Ordering::Relaxed), 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] #[inline]
#[$stable_cxchg] #[$stable_cxchg]
#[$cfg_cas] #[$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] #[inline]
#[$stable_cxchg] #[$stable_cxchg]
#[$cfg_cas] #[$cfg_cas]
@@ -3246,13 +3349,16 @@ macro_rules! atomic_int {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of /// critical section or mutex.
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] ///
/// and suffers from the same drawbacks. /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// In particular, this method will not circumvent the [ABA Problem]. /// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -3309,13 +3415,16 @@ macro_rules! atomic_int {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// This method is not magic; it is not provided by the hardware, and does not act like a
/// It is implemented in terms of /// critical section or mutex.
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] ///
/// and suffers from the same drawbacks. /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// In particular, this method will not circumvent the [ABA Problem]. /// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///
@@ -3367,13 +3476,17 @@ macro_rules! atomic_int {
/// ///
/// # Considerations /// # Considerations
/// ///
/// This method is not magic; it is not provided by the hardware. /// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// It is implemented in terms of /// This method is not magic; it is not provided by the hardware, and does not act like a
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] /// critical section or mutex.
/// and suffers from the same drawbacks. ///
/// In particular, this method will not circumvent the [ABA Problem]. /// 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 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// ///
/// # Examples /// # Examples
/// ///

View File

@@ -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. 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 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-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, * `-Zmiri-disable-isolation` disables host isolation. As a consequence,
the program has access to host resources such as environment variables, file the program has access to host resources such as environment variables, file
systems, and randomness. systems, and randomness.

View File

@@ -601,6 +601,8 @@ fn main() {
miri_config.collect_leak_backtraces = false; miri_config.collect_leak_backtraces = false;
} else if arg == "-Zmiri-force-intrinsic-fallback" { } else if arg == "-Zmiri-force-intrinsic-fallback" {
miri_config.force_intrinsic_fallback = true; miri_config.force_intrinsic_fallback = true;
} else if arg == "-Zmiri-deterministic-floats" {
miri_config.float_nondet = false;
} else if arg == "-Zmiri-strict-provenance" { } else if arg == "-Zmiri-strict-provenance" {
miri_config.provenance_mode = ProvenanceMode::Strict; miri_config.provenance_mode = ProvenanceMode::Strict;
} else if arg == "-Zmiri-permissive-provenance" { } else if arg == "-Zmiri-permissive-provenance" {

View File

@@ -166,6 +166,8 @@ pub struct MiriConfig {
pub fixed_scheduling: bool, pub fixed_scheduling: bool,
/// Always prefer the intrinsic fallback body over the native Miri implementation. /// Always prefer the intrinsic fallback body over the native Miri implementation.
pub force_intrinsic_fallback: bool, pub force_intrinsic_fallback: bool,
/// Whether floating-point operations can behave non-deterministically.
pub float_nondet: bool,
} }
impl Default for MiriConfig { impl Default for MiriConfig {
@@ -205,6 +207,7 @@ impl Default for MiriConfig {
address_reuse_cross_thread_rate: 0.1, address_reuse_cross_thread_rate: 0.1,
fixed_scheduling: false, fixed_scheduling: false,
force_intrinsic_fallback: false, force_intrinsic_fallback: false,
float_nondet: true,
} }
} }
} }

View File

@@ -293,7 +293,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let a = this.read_scalar(a)?.to_f32()?; let a = this.read_scalar(a)?.to_f32()?;
let b = this.read_scalar(b)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?;
let c = this.read_scalar(c)?.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 { let res = if fuse {
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 // 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() 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 a = this.read_scalar(a)?.to_f64()?;
let b = this.read_scalar(b)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?;
let c = this.read_scalar(c)?.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 { let res = if fuse {
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 // 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() a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()

View File

@@ -306,7 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let c = this.read_scalar(&this.project_index(&c, i)?)?; let c = this.read_scalar(&this.project_index(&c, i)?)?;
let dest = this.project_index(&dest, 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. // Works for f32 and f64.
// FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468. // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468.

View File

@@ -618,6 +618,9 @@ pub struct MiriMachine<'tcx> {
/// Always prefer the intrinsic fallback body over the native Miri implementation. /// Always prefer the intrinsic fallback body over the native Miri implementation.
pub force_intrinsic_fallback: bool, pub force_intrinsic_fallback: bool,
/// Whether floating-point operations can behave non-deterministically.
pub float_nondet: bool,
} }
impl<'tcx> MiriMachine<'tcx> { impl<'tcx> MiriMachine<'tcx> {
@@ -778,6 +781,7 @@ impl<'tcx> MiriMachine<'tcx> {
int2ptr_warned: Default::default(), int2ptr_warned: Default::default(),
mangle_internal_symbol_cache: Default::default(), mangle_internal_symbol_cache: Default::default(),
force_intrinsic_fallback: config.force_intrinsic_fallback, force_intrinsic_fallback: config.force_intrinsic_fallback,
float_nondet: config.float_nondet,
} }
} }
@@ -956,6 +960,7 @@ impl VisitProvenance for MiriMachine<'_> {
int2ptr_warned: _, int2ptr_warned: _,
mangle_internal_symbol_cache: _, mangle_internal_symbol_cache: _,
force_intrinsic_fallback: _, force_intrinsic_fallback: _,
float_nondet: _,
} = self; } = self;
threads.visit_provenance(visit); threads.visit_provenance(visit);

View File

@@ -15,6 +15,10 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
val: F, val: F,
err_scale: i32, err_scale: i32,
) -> F { ) -> F {
if !ecx.machine.float_nondet {
return val;
}
let rng = ecx.machine.rng.get_mut(); let rng = ecx.machine.rng.get_mut();
// Generate a random integer in the range [0, 2^PREC). // Generate a random integer in the range [0, 2^PREC).
// (When read as binary, the position of the first `1` determines the exponent, // (When read as binary, the position of the first `1` determines the exponent,

View File

@@ -76,6 +76,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
} }
fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 { 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. /// Make the given NaN a signaling NaN.
/// Returns `None` if this would not result in a NaN. /// Returns `None` if this would not result in a NaN.
fn make_signaling<F: Float>(f: F) -> Option<F> { 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 } if f.is_nan() { Some(f) } else { None }
} }
let this = self.eval_context_ref();
let mut rand = this.machine.rng.borrow_mut(); let mut rand = this.machine.rng.borrow_mut();
// Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation. // 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 // 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 { fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F {
let this = self.eval_context_ref(); let this = self.eval_context_ref();
if !this.machine.float_nondet {
return a;
}
// Return one side non-deterministically. // Return one side non-deterministically.
let mut rand = this.machine.rng.borrow_mut(); let mut rand = this.machine.rng.borrow_mut();
if rand.random() { a } else { b } if rand.random() { a } else { b }

View File

@@ -1,5 +1,7 @@
#[rustc_do_not_const_check] #[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() {} const fn foo() {}
fn main() {} fn main() {}

View File

@@ -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 --> $DIR/gate-do-not-const-check.rs:1:1
| |
LL | #[rustc_do_not_const_check] LL | #[rustc_do_not_const_check]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 1 previous error

View 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 {}

View 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

View File

@@ -12,6 +12,8 @@ trait ImportantTrait2 {}
#[diagnostic::on_unimplemented(message = "Test {1:}")] #[diagnostic::on_unimplemented(message = "Test {1:}")]
//~^WARN positional format arguments are not allowed here //~^WARN positional format arguments are not allowed here
//~|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 {} trait ImportantTrait3 {}
#[diagnostic::on_unimplemented(message = "Test {Self:123}")] #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
@@ -20,17 +22,22 @@ trait ImportantTrait3 {}
trait ImportantTrait4 {} trait ImportantTrait4 {}
#[diagnostic::on_unimplemented(message = "Test {Self:!}")] #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
//~^WARN expected `}`, found `!` //~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
//~|WARN expected `}`, found `!` //~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
//~|WARN unmatched `}` found
//~|WARN unmatched `}` found
trait ImportantTrait5 {} 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_1(_: impl ImportantTrait1) {}
fn check_2(_: impl ImportantTrait2) {} fn check_2(_: impl ImportantTrait2) {}
fn check_3(_: impl ImportantTrait3) {} fn check_3(_: impl ImportantTrait3) {}
fn check_4(_: impl ImportantTrait4) {} fn check_4(_: impl ImportantTrait4) {}
fn check_5(_: impl ImportantTrait5) {} fn check_5(_: impl ImportantTrait5) {}
fn check_6(_: impl ImportantTrait6) {}
fn main() { fn main() {
check_1(()); check_1(());
@@ -42,5 +49,7 @@ fn main() {
check_4(()); check_4(());
//~^ERROR Test () //~^ERROR Test ()
check_5(()); check_5(());
//~^ERROR Test {Self:!} //~^ERROR Test ()
check_6(());
//~^ERROR Test ()
} }

View File

@@ -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 = 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 warning: positional format arguments are not allowed here
--> $DIR/broken_format.rs:12:49 --> $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 = help: only named format arguments with the name of one of the generic types are allowed in this context
warning: invalid format specifier warning: invalid format specifier
--> $DIR/broken_format.rs:17:42 --> $DIR/broken_format.rs:19:53
| |
LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
| ^^^^^^^^^^^^^^^^^ | ^^^^
| |
= help: no format specifier are supported in this position = help: no format specifier are supported in this position
warning: expected `}`, found `!` warning: invalid format specifier
--> $DIR/broken_format.rs:22:42 --> $DIR/broken_format.rs:24: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 warning: invalid format specifier
--> $DIR/broken_format.rs:22:42 --> $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 warning: unmatched `}` found
--> $DIR/broken_format.rs:2:42 --> $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` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: {{Test } thing error[E0277]: {{Test } thing
--> $DIR/broken_format.rs:36:13 --> $DIR/broken_format.rs:43:13
| |
LL | check_1(()); LL | check_1(());
| ------- ^^ the trait `ImportantTrait1` is not implemented for `()` | ------- ^^ the trait `ImportantTrait1` is not implemented for `()`
@@ -64,7 +76,7 @@ help: this trait has no implementations, consider adding one
LL | trait ImportantTrait1 {} LL | trait ImportantTrait1 {}
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check_1` 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) {} LL | fn check_1(_: impl ImportantTrait1) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check_1` | ^^^^^^^^^^^^^^^ 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` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: Test {} error[E0277]: Test {}
--> $DIR/broken_format.rs:38:13 --> $DIR/broken_format.rs:45:13
| |
LL | check_2(()); LL | check_2(());
| ------- ^^ the trait `ImportantTrait2` is not implemented for `()` | ------- ^^ the trait `ImportantTrait2` is not implemented for `()`
@@ -92,11 +104,20 @@ help: this trait has no implementations, consider adding one
LL | trait ImportantTrait2 {} LL | trait ImportantTrait2 {}
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check_2` 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) {} LL | fn check_2(_: impl ImportantTrait2) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check_2` | ^^^^^^^^^^^^^^^ 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 warning: positional format arguments are not allowed here
--> $DIR/broken_format.rs:12:49 --> $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` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: Test {1} error[E0277]: Test {1}
--> $DIR/broken_format.rs:40:13 --> $DIR/broken_format.rs:47:13
| |
LL | check_3(()); LL | check_3(());
| ------- ^^ the trait `ImportantTrait3` is not implemented for `()` | ------- ^^ the trait `ImportantTrait3` is not implemented for `()`
@@ -115,27 +136,27 @@ LL | check_3(());
| required by a bound introduced by this call | required by a bound introduced by this call
| |
help: this trait has no implementations, consider adding one help: this trait has no implementations, consider adding one
--> $DIR/broken_format.rs:15:1 --> $DIR/broken_format.rs:17:1
| |
LL | trait ImportantTrait3 {} LL | trait ImportantTrait3 {}
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check_3` 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) {} LL | fn check_3(_: impl ImportantTrait3) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check_3` | ^^^^^^^^^^^^^^^ required by this bound in `check_3`
warning: invalid format specifier warning: invalid format specifier
--> $DIR/broken_format.rs:17:42 --> $DIR/broken_format.rs:19:53
| |
LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
| ^^^^^^^^^^^^^^^^^ | ^^^^
| |
= help: no format specifier are supported in this position = help: no format specifier are supported in this position
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: Test () error[E0277]: Test ()
--> $DIR/broken_format.rs:42:13 --> $DIR/broken_format.rs:49:13
| |
LL | check_4(()); LL | check_4(());
| ------- ^^ the trait `ImportantTrait4` is not implemented for `()` | ------- ^^ the trait `ImportantTrait4` is not implemented for `()`
@@ -143,34 +164,27 @@ LL | check_4(());
| required by a bound introduced by this call | required by a bound introduced by this call
| |
help: this trait has no implementations, consider adding one help: this trait has no implementations, consider adding one
--> $DIR/broken_format.rs:20:1 --> $DIR/broken_format.rs:22:1
| |
LL | trait ImportantTrait4 {} LL | trait ImportantTrait4 {}
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check_4` 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) {} LL | fn check_4(_: impl ImportantTrait4) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check_4` | ^^^^^^^^^^^^^^^ required by this bound in `check_4`
warning: expected `}`, found `!` warning: invalid format specifier
--> $DIR/broken_format.rs:22:42 --> $DIR/broken_format.rs:24:53
| |
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] 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` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: unmatched `}` found error[E0277]: Test ()
--> $DIR/broken_format.rs:22:42 --> $DIR/broken_format.rs:51:13
|
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
| |
LL | check_5(()); LL | check_5(());
| ------- ^^ the trait `ImportantTrait5` is not implemented for `()` | ------- ^^ the trait `ImportantTrait5` is not implemented for `()`
@@ -183,11 +197,39 @@ help: this trait has no implementations, consider adding one
LL | trait ImportantTrait5 {} LL | trait ImportantTrait5 {}
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check_5` 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) {} LL | fn check_5(_: impl ImportantTrait5) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check_5` | ^^^^^^^^^^^^^^^ 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`. For more information about this error, try `rustc --explain E0277`.

View File

@@ -1,6 +1,8 @@
// check that `pattern_complexity_limit` is feature-gated // check that `pattern_complexity_limit` is feature-gated
#![pattern_complexity_limit = "42"] #![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() {} fn main() {}

View File

@@ -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 --> $DIR/feature-gate-pattern-complexity-limit.rs:3:1
| |
LL | #![pattern_complexity_limit = "42"] LL | #![pattern_complexity_limit = "42"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 1 previous error

View File

@@ -1,6 +1,12 @@
// Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate. // 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_variance]
#[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 //~^ 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() {} fn main() {}

View File

@@ -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 --> $DIR/feature-gate-rustc-attrs-1.rs:3:1
| |
LL | #[rustc_variance] LL | #[rustc_variance]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error[E0658]: use of an internal attribute
(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:7:1
--> $DIR/feature-gate-rustc-attrs-1.rs:4:1
| |
LL | #[rustc_nonnull_optimization_guaranteed] LL | #[rustc_nonnull_optimization_guaranteed]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 2 previous errors

View File

@@ -8,15 +8,19 @@ mod unknown { pub macro rustc() {} }
#[rustc::unknown] #[rustc::unknown]
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
//~| ERROR expected attribute, found macro `rustc::unknown` //~| ERROR expected attribute, found macro `rustc::unknown`
//~| NOTE not an attribute
fn f() {} fn f() {}
#[unknown::rustc] #[unknown::rustc]
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
//~| ERROR expected attribute, found macro `unknown::rustc` //~| ERROR expected attribute, found macro `unknown::rustc`
//~| NOTE not an attribute
fn g() {} fn g() {}
#[rustc_dummy] #[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] #[rustc_unknown]
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
//~| ERROR cannot find attribute `rustc_unknown` in this scope //~| ERROR cannot find attribute `rustc_unknown` in this scope

View File

@@ -11,37 +11,38 @@ LL | #[rustc::unknown]
| ^^^^^^^^^^^^^^ not an attribute | ^^^^^^^^^^^^^^ not an attribute
error: attributes starting with `rustc` are reserved for use by the `rustc` compiler 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] LL | #[unknown::rustc]
| ^^^^^ | ^^^^^
error: expected attribute, found macro `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] LL | #[unknown::rustc]
| ^^^^^^^^^^^^^^ not an attribute | ^^^^^^^^^^^^^^ not an attribute
error: attributes starting with `rustc` are reserved for use by the `rustc` compiler 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] LL | #[rustc_unknown]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: cannot find attribute `rustc_unknown` in this scope 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] LL | #[rustc_unknown]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error[E0658]: the `#[rustc_dummy]` 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.rs:18:1 --> $DIR/feature-gate-rustc-attrs.rs:20:1
| |
LL | #[rustc_dummy] LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 7 previous errors

View File

@@ -11,9 +11,11 @@
#![macro_export] #![macro_export]
//~^ ERROR: `macro_export` attribute cannot be used at crate level //~^ 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 //~^ 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()] #![repr()]
//~^ ERROR: `repr` attribute cannot be used at crate level //~^ ERROR: `repr` attribute cannot be used at crate level
#![path = "3800"] #![path = "3800"]

View File

@@ -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 --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1
| |
LL | #![rustc_main] LL | #![rustc_main]
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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)]` 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() { } LL | #[inline = "2100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
@@ -18,7 +19,7 @@ LL | #[inline = "2100"] fn f() { }
= note: `#[deny(ill_formed_attribute_input)]` on by default = note: `#[deny(ill_formed_attribute_input)]` on by default
error[E0518]: attribute should be applied to function or closure 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] LL | #[inline]
| ^^^^^^^^^ | ^^^^^^^^^
@@ -29,7 +30,7 @@ LL | | }
| |_- not a function or closure | |_- not a function or closure
error: attribute should be applied to an `extern crate` item 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] LL | #[no_link]
| ^^^^^^^^^^ | ^^^^^^^^^^
@@ -43,7 +44,7 @@ LL | | }
| |_- not an `extern crate` item | |_- not an `extern crate` item
error: attribute should be applied to 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:89:1 --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1
| |
LL | #[export_name = "2200"] LL | #[export_name = "2200"]
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +58,7 @@ LL | | }
| |_- not a free function, impl method or static | |_- not a free function, impl method or static
error[E0517]: attribute should be applied to 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:123:8 --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:8
| |
LL | #[repr(C)] LL | #[repr(C)]
| ^ | ^
@@ -70,7 +71,7 @@ LL | | }
| |_- not a struct, enum, or union | |_- not a struct, enum, or union
error[E0517]: attribute should be applied to 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)] LL | #[repr(Rust)]
| ^^^^ | ^^^^
@@ -83,19 +84,19 @@ LL | | }
| |_- not a struct, enum, or union | |_- not a struct, enum, or union
error: attribute should be applied to an `extern crate` item 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] LL | #![no_link]
| ^^^^^^^^^^^ not an `extern crate` item | ^^^^^^^^^^^ not an `extern crate` item
error: attribute should be applied to 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:26:1 --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
| |
LL | #![export_name = "2200"] LL | #![export_name = "2200"]
| ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static
error[E0518]: attribute should be applied to function or closure 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] LL | #![inline]
| ^^^^^^^^^^ not a function or closure | ^^^^^^^^^^ not a function or closure
@@ -131,7 +132,7 @@ LL + #[rustc_main]
| |
error: `path` attribute cannot be used at crate level 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"] LL | #![path = "3800"]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
@@ -146,7 +147,7 @@ LL + #[path = "3800"]
| |
error: `automatically_derived` attribute cannot be used at crate level 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] LL | #![automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -161,7 +162,7 @@ LL + #[automatically_derived]
| |
error: `repr` attribute cannot be used at crate level 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()] LL | #![repr()]
| ^^^^^^^^^^ | ^^^^^^^^^^
@@ -176,139 +177,139 @@ LL + #[repr()]
| |
error[E0518]: attribute should be applied to function or closure 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] } LL | mod inner { #![inline] }
| ------------^^^^^^^^^^-- not a function or closure | ------------^^^^^^^^^^-- not a function or closure
error[E0518]: attribute should be applied to 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; LL | #[inline] struct S;
| ^^^^^^^^^ --------- not a function or closure | ^^^^^^^^^ --------- not a function or closure
error[E0518]: attribute should be applied to 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; LL | #[inline] type T = S;
| ^^^^^^^^^ ----------- not a function or closure | ^^^^^^^^^ ----------- not a function or closure
error[E0518]: attribute should be applied to 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 { } LL | #[inline] impl S { }
| ^^^^^^^^^ ---------- not a function or closure | ^^^^^^^^^ ---------- not a function or closure
error: attribute should be applied to an `extern crate` item 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] } LL | mod inner { #![no_link] }
| ------------^^^^^^^^^^^-- not an `extern crate` item | ------------^^^^^^^^^^^-- not an `extern crate` item
error: attribute should be applied to 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() { } LL | #[no_link] fn f() { }
| ^^^^^^^^^^ ---------- not an `extern crate` item | ^^^^^^^^^^ ---------- not an `extern crate` item
error: attribute should be applied to 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; LL | #[no_link] struct S;
| ^^^^^^^^^^ --------- not an `extern crate` item | ^^^^^^^^^^ --------- not an `extern crate` item
error: attribute should be applied to 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; LL | #[no_link]type T = S;
| ^^^^^^^^^^----------- not an `extern crate` item | ^^^^^^^^^^----------- not an `extern crate` item
error: attribute should be applied to 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 { } LL | #[no_link] impl S { }
| ^^^^^^^^^^ ---------- not an `extern crate` item | ^^^^^^^^^^ ---------- not an `extern crate` item
error: attribute should be applied to 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:94:17 --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17
| |
LL | mod inner { #![export_name="2200"] } LL | mod inner { #![export_name="2200"] }
| ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static
error: attribute should be applied to 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; LL | #[export_name = "2200"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
error: attribute should be applied to 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; LL | #[export_name = "2200"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
error: attribute should be applied to 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 { } LL | #[export_name = "2200"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static
error: attribute should be applied to 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(); LL | #[export_name = "2200"] fn foo();
| ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
error: attribute should be applied to 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() {} LL | #[export_name = "2200"] fn bar() {}
| ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
error[E0517]: attribute should be applied to 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:127:25 --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:25
| |
LL | mod inner { #![repr(C)] } LL | mod inner { #![repr(C)] }
| --------------------^---- not a struct, enum, or union | --------------------^---- not a struct, enum, or union
error[E0517]: attribute should be applied to 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() { } LL | #[repr(C)] fn f() { }
| ^ ---------- not a struct, enum, or union | ^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to 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; LL | #[repr(C)] type T = S;
| ^ ----------- not a struct, enum, or union | ^ ----------- not a struct, enum, or union
error[E0517]: attribute should be applied to 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 { } LL | #[repr(C)] impl S { }
| ^ ---------- not a struct, enum, or union | ^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to 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)] } LL | mod inner { #![repr(Rust)] }
| --------------------^^^^---- not a struct, enum, or union | --------------------^^^^---- not a struct, enum, or union
error[E0517]: attribute should be applied to 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() { } LL | #[repr(Rust)] fn f() { }
| ^^^^ ---------- not a struct, enum, or union | ^^^^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to 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; LL | #[repr(Rust)] type T = S;
| ^^^^ ----------- not a struct, enum, or union | ^^^^ ----------- not a struct, enum, or union
error[E0517]: attribute should be applied to 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 { } LL | #[repr(Rust)] impl S { }
| ^^^^ ---------- not a struct, enum, or union | ^^^^ ---------- not a struct, enum, or union

View File

@@ -2,11 +2,15 @@
#![allow(internal_features)] #![allow(internal_features)]
#[rustc_force_inline] #[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() { pub fn bare() {
} }
#[rustc_force_inline = "the test requires it"] #[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() { pub fn justified() {
} }

View File

@@ -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 --> $DIR/gate.rs:4:1
| |
LL | #[rustc_force_inline] LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error[E0658]: use of an internal attribute
--> $DIR/gate.rs:9:1 --> $DIR/gate.rs:11:1
| |
LL | #[rustc_force_inline = "the test requires it"] LL | #[rustc_force_inline = "the test requires it"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 2 previous errors

View File

@@ -1,8 +1,9 @@
// Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate. // Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate.
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
//~^ ERROR this is an internal attribute that will never be stable //~^ ERROR use of an internal attribute [E0658]
trait Foo<Bar> //~| 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() {} fn main() {}

View File

@@ -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 --> $DIR/feature-gate-on-unimplemented.rs:3:1
| |
LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 1 previous error

View File

@@ -1,5 +1,7 @@
#[rustc_doc_primitive = "usize"] #[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 /// Some docs
mod usize {} mod usize {}

View File

@@ -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 --> $DIR/feature-gate-doc_primitive.rs:1:1
| |
LL | #[rustc_doc_primitive = "usize"] LL | #[rustc_doc_primitive = "usize"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 1 previous error

View File

@@ -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; struct Foomp;
fn main() {} fn main() {}

View File

@@ -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 --> $DIR/diagnostic_item.rs:1:1
| |
LL | #[rustc_diagnostic_item = "foomp"] LL | #[rustc_diagnostic_item = "foomp"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 1 previous error

View File

@@ -1,5 +1,7 @@
#[rustc_must_implement_one_of(eq, neq)] #[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 { trait Equal {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
!self.neq(other) !self.neq(other)

View File

@@ -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 --> $DIR/rustc_must_implement_one_of_gated.rs:1:1
| |
LL | #[rustc_must_implement_one_of(eq, neq)] LL | #[rustc_must_implement_one_of(eq, neq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = 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 error: aborting due to 1 previous error