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();
}
}};
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
for note in $notes {
diag.note(*note);
}
diag.emit();
}
}};
}
/// The case involving a multispan.
@@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check feature gates for built-in attributes.
if let Some(BuiltinAttribute {
gate: AttributeGate::Gated(_, name, descr, has_feature),
gate: AttributeGate::Gated { feature, message, check, notes, .. },
..
}) = attr_info
{
gate_alt!(self, has_feature(self.features), *name, attr.span, *descr);
gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
}
// Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) {

View File

@@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_span::edition::Edition;
use rustc_span::{Symbol, sym};
use crate::{Features, Stability};
use crate::Features;
type GateFn = fn(&Features) -> bool;
@@ -94,34 +94,23 @@ pub enum AttributeSafety {
Unsafe { unsafe_since: Option<Edition> },
}
#[derive(Clone, Copy)]
#[derive(Clone, Debug, Copy)]
pub enum AttributeGate {
/// Is gated by a given feature gate, reason
/// and function to check if enabled
Gated(Stability, Symbol, &'static str, fn(&Features) -> bool),
/// A gated attribute which requires a feature gate to be enabled.
Gated {
/// The feature gate, for example `#![feature(rustc_attrs)]` for rustc_* attributes.
feature: Symbol,
/// The error message displayed when an attempt is made to use the attribute without its feature gate.
message: &'static str,
/// Check function to be called during the `PostExpansionVisitor` pass.
check: fn(&Features) -> bool,
/// Notes to be displayed when an attempt is made to use the attribute without its feature gate.
notes: &'static [&'static str],
},
/// Ungated attribute, can be used on all release channels
Ungated,
}
// fn() is not Debug
impl std::fmt::Debug for AttributeGate {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Self::Gated(ref stab, name, expl, _) => {
write!(fmt, "Gated({stab:?}, {name}, {expl})")
}
Self::Ungated => write!(fmt, "Ungated"),
}
}
}
impl AttributeGate {
fn is_deprecated(&self) -> bool {
matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..))
}
}
/// A template that the attribute input must match.
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
#[derive(Clone, Copy, Default)]
@@ -247,7 +236,7 @@ macro_rules! ungated {
}
macro_rules! gated {
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
@@ -255,10 +244,15 @@ macro_rules! gated {
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
gate: Gated {
feature: sym::$gate,
message: $message,
check: Features::$gate,
notes: &[],
},
}
};
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
@@ -266,10 +260,15 @@ macro_rules! gated {
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
gate: Gated {
feature: sym::$attr,
message: $message,
check: Features::$attr,
notes: &[],
},
}
};
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
@@ -277,10 +276,15 @@ macro_rules! gated {
safety: AttributeSafety::Normal,
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
gate: Gated {
feature: sym::$gate,
message: $message,
check: Features::$gate,
notes: &[],
},
}
};
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
@@ -288,7 +292,12 @@ macro_rules! gated {
safety: AttributeSafety::Normal,
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
gate: Gated {
feature: sym::$attr,
message: $message,
check: Features::$attr,
notes: &[],
},
}
};
}
@@ -304,12 +313,11 @@ macro_rules! rustc_attr {
concat!(
"the `#[",
stringify!($attr),
"]` attribute is just used for rustc unit tests \
and will never be stable",
"]` attribute is used for rustc unit tests"
),
)
};
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
@@ -317,7 +325,17 @@ macro_rules! rustc_attr {
safety: AttributeSafety::Normal,
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs),
gate: Gated {
feature: sym::rustc_attrs,
message: "use of an internal attribute",
check: Features::rustc_attrs,
notes: &[
concat!("the `#[",
stringify!($attr),
"]` attribute is an internal implementation detail that will never be stable"),
$($notes),*
]
},
}
};
}
@@ -328,9 +346,6 @@ macro_rules! experimental {
};
}
const IMPL_DETAIL: &str = "internal implementation detail";
const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
#[derive(PartialEq)]
pub enum EncodeCrossCrate {
Yes,
@@ -668,7 +683,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
ErrorFollowing, EncodeCrossCrate::Yes,
"rustc_deprecated_safe_2024 is supposed to be used in libstd only",
"`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
),
rustc_attr!(
rustc_pub_transparent, Normal, template!(Word),
@@ -695,7 +710,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ErrorFollowing,
EncodeCrossCrate::No,
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
never type stabilization, and will never be stable"
never type stabilization"
),
// ==========================================================================
@@ -704,23 +719,23 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_allocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_nounwind, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_reallocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_deallocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL
EncodeCrossCrate::No,
),
gated!(
default_lib_allocator, Normal, template!(Word), WarnFollowing,
@@ -762,7 +777,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
rustc_attr!(
rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, INTERNAL_UNSTABLE
EncodeCrossCrate::No,
),
// ==========================================================================
@@ -772,11 +787,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_builtin_macro, Normal,
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
EncodeCrossCrate::Yes, IMPL_DETAIL
EncodeCrossCrate::Yes,
),
rustc_attr!(
rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, INTERNAL_UNSTABLE
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_macro_transparency, Normal,
@@ -786,7 +801,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_autodiff, Normal,
template!(Word, List: r#""...""#), DuplicatesOk,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
EncodeCrossCrate::Yes,
),
// Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
// The attributes are not gated, to avoid stability errors, but they cannot be used in stable
@@ -812,54 +827,53 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
NameValueStr: "message"
),
ErrorFollowing, EncodeCrossCrate::Yes,
INTERNAL_UNSTABLE
"see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
),
rustc_attr!(
rustc_confusables, Normal,
template!(List: r#""name1", "name2", ..."#),
ErrorFollowing, EncodeCrossCrate::Yes,
INTERNAL_UNSTABLE,
),
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
rustc_attr!(
rustc_conversion_suggestion, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
WarnFollowing, EncodeCrossCrate::Yes,
),
// Prevents field reads in the marked trait or method to be considered
// during dead code analysis.
rustc_attr!(
rustc_trivial_field_reads, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::potential_query_instability` lint to warn methods which
// might not be stable during incremental compilation.
rustc_attr!(
rustc_lint_query_instability, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::untracked_query_information` lint to warn methods which
// might not be stable during incremental compilation.
rustc_attr!(
rustc_lint_untracked_query_information, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
// APIs. Any function with this attribute will be checked by that lint.
rustc_attr!(
rustc_lint_diagnostics, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
// types (as well as any others in future).
rustc_attr!(
rustc_lint_opt_ty, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::bad_opt_access` lint on fields
// types (as well as any others in future).
rustc_attr!(
rustc_lint_opt_deny_field_access, Normal, template!(List: "message"),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
WarnFollowing, EncodeCrossCrate::Yes,
),
// ==========================================================================
@@ -868,28 +882,30 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_promotable, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL),
EncodeCrossCrate::No, ),
rustc_attr!(
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
EncodeCrossCrate::Yes,
),
// Do not const-check this function's body. It will always get replaced during CTFE.
rustc_attr!(
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
),
// Ensure the argument to this function is &&str during const-check.
rustc_attr!(
rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
EncodeCrossCrate::Yes, "`#[rustc_const_panic_str]` ensures the argument to this function is &&str during const-check",
),
rustc_attr!(
rustc_const_stable_indirect, Normal,
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
template!(Word),
WarnFollowing,
EncodeCrossCrate::No,
"this is an internal implementation detail",
),
rustc_attr!(
rustc_intrinsic_const_stable_indirect, Normal,
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
),
gated!(
rustc_allow_const_fn_unstable, Normal,
@@ -905,21 +921,21 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
EncodeCrossCrate::Yes,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in libcore and libstd and will never be stable",
niche optimizations in the standard library",
),
rustc_attr!(
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
EncodeCrossCrate::Yes,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in libcore and libstd and will never be stable",
niche optimizations in the standard library",
),
rustc_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes,
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
guaranteed niche optimizations in libcore and libstd and will never be stable\n\
(note that the compiler does not even check whether the type indeed is being non-null-optimized; \
it is your responsibility to ensure that the attribute is only used on types that are optimized)",
guaranteed niche optimizations in the standard library",
"the compiler does not even check whether the type indeed is being non-null-optimized; \
it is your responsibility to ensure that the attribute is only used on types that are optimized",
),
// ==========================================================================
@@ -932,17 +948,17 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations."
),
rustc_attr!(
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference."
),
rustc_attr!(
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers."
),
rustc_attr!(
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
@@ -950,15 +966,15 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
rustc_attr!(
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`."
),
rustc_attr!(
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver."
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver."
),
rustc_attr!(
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl."
),
rustc_attr!(
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
@@ -970,7 +986,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(Word),
ErrorFollowing,
EncodeCrossCrate::No,
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
"`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls"
),
rustc_attr!(
rustc_do_not_implement_via_object,
@@ -978,14 +994,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(Word),
ErrorFollowing,
EncodeCrossCrate::No,
"#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
"`#[rustc_do_not_implement_via_object]` opts out of the automatic trait impl for trait objects \
(`impl Trait for dyn Trait`)"
),
rustc_attr!(
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes,
"#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`."
),
BuiltinAttribute {
@@ -996,12 +1012,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
safety: AttributeSafety::Normal,
template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing,
gate: Gated(
Stability::Unstable,
sym::rustc_attrs,
"diagnostic items compiler internal support for linting",
Features::rustc_attrs,
),
gate: Gated{
feature: sym::rustc_attrs,
message: "use of an internal attribute",
check: Features::rustc_attrs,
notes: &["the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types \
from the standard library for diagnostic purposes"],
},
},
gated!(
// Used in resolve:
@@ -1015,14 +1032,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
overflow checking behavior of several libcore functions that are inlined \
across crates and will never be stable",
overflow checking behavior of several functions in the standard library that are inlined \
across crates",
),
rustc_attr!(
rustc_reservation_impl, Normal,
template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
"the `#[rustc_reservation_impl]` attribute is internally used \
for reserving for `for<T> From<!> for T` impl"
for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`"
),
rustc_attr!(
rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
@@ -1053,12 +1070,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
ErrorFollowing, EncodeCrossCrate::No,
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
definition of a trait, it's currently in experimental form and should be changed before \
being exposed outside of the std"
definition of a trait. Its syntax and semantics are highly experimental and will be \
subject to change before stabilization",
),
rustc_attr!(
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#,
EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \
to provide a way to generate documentation for primitive types",
),
gated!(
rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
@@ -1066,11 +1084,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
rustc_attr!(
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
"`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
),
rustc_attr!(
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
"#[rustc_force_inline] forces a free function to be inlined"
"`#[rustc_force_inline]` forces a free function to be inlined"
),
// ==========================================================================
@@ -1209,10 +1227,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
];
pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
}
pub fn is_builtin_attr_name(name: Symbol) -> bool {
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
}

View File

@@ -40,14 +40,6 @@ pub struct Feature {
issue: Option<NonZero<u32>>,
}
#[derive(Copy, Clone, Debug)]
pub enum Stability {
Unstable,
// First argument is tracking issue link; second argument is an optional
// help message, which defaults to "remove this attribute".
Deprecated(&'static str, Option<&'static str>),
}
#[derive(Clone, Copy, Debug, Hash)]
pub enum UnstableFeatures {
/// Disallow use of unstable features, as on beta/stable channels.
@@ -144,9 +136,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
pub use accepted::ACCEPTED_LANG_FEATURES;
pub use builtin_attrs::{
AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes,
encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
is_valid_for_get_attr,
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate,
find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr,
};
pub use removed::REMOVED_LANG_FEATURES;
pub use unstable::{

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_method = declaration of an `unsafe` method
lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
.msg_suggestion = {$msg}
.default_suggestion = remove this attribute
lint_builtin_deref_nullptr = dereferencing a null pointer
.label = this code causes undefined behavior when executed

View File

@@ -22,7 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind};
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust::expr_to_string;
use rustc_errors::{Applicability, LintDiagnostic};
use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes};
use rustc_feature::GateIssue;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
@@ -48,8 +48,7 @@ use rustc_trait_selection::traits::{self};
use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
use crate::lints::{
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDerefNullptr, BuiltinDoubleNegations,
BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
@@ -799,53 +798,6 @@ impl EarlyLintPass for AnonymousParameters {
}
}
/// Check for use of attributes which have been deprecated.
#[derive(Clone)]
pub struct DeprecatedAttr {
// This is not free to compute, so we want to keep it around, rather than
// compute it for every attribute.
depr_attrs: Vec<&'static BuiltinAttribute>,
}
impl_lint_pass!(DeprecatedAttr => []);
impl Default for DeprecatedAttr {
fn default() -> Self {
DeprecatedAttr { depr_attrs: deprecated_attributes() }
}
}
impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
if attr.ident().map(|ident| ident.name) == Some(*name) {
if let &AttributeGate::Gated(
Stability::Deprecated(link, suggestion),
name,
reason,
_,
) = gate
{
let suggestion = match suggestion {
Some(msg) => {
BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg }
}
None => {
BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span }
}
};
cx.emit_span_lint(
DEPRECATED,
attr.span,
BuiltinDeprecatedAttrLink { name, reason, link, suggestion },
);
}
return;
}
}
}
}
fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
use rustc_ast::token::CommentKind;

View File

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

View File

@@ -199,32 +199,6 @@ pub(crate) struct BuiltinAnonymousParams<'a> {
pub ty_snip: &'a str,
}
// FIXME(davidtwco) translatable deprecated attr
#[derive(LintDiagnostic)]
#[diag(lint_builtin_deprecated_attr_link)]
pub(crate) struct BuiltinDeprecatedAttrLink<'a> {
pub name: Symbol,
pub reason: &'a str,
pub link: &'a str,
#[subdiagnostic]
pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>,
}
#[derive(Subdiagnostic)]
pub(crate) enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
#[suggestion(lint_msg_suggestion, code = "", applicability = "machine-applicable")]
Msg {
#[primary_span]
suggestion: Span,
msg: &'a str,
},
#[suggestion(lint_default_suggestion, code = "", applicability = "machine-applicable")]
Default {
#[primary_span]
suggestion: Span,
},
}
#[derive(LintDiagnostic)]
#[diag(lint_builtin_unused_doc_comment)]
pub(crate) struct BuiltinUnusedDocComment<'a> {

View File

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

View File

@@ -553,3 +553,45 @@ fn asm_concat() {
assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]);
assert_eq!(parser.line_spans, &[]);
}
#[test]
fn diagnostic_format_flags() {
let lit = "{thing:blah}";
let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic);
assert!(!parser.is_source_literal);
let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() };
assert_eq!(
**arg,
Argument {
position: ArgumentNamed("thing"),
position_span: 2..7,
format: FormatSpec { ty: ":blah", ty_span: Some(7..12), ..Default::default() },
}
);
assert_eq!(parser.line_spans, &[]);
assert!(parser.errors.is_empty());
}
#[test]
fn diagnostic_format_mod() {
let lit = "{thing:+}";
let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic);
assert!(!parser.is_source_literal);
let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() };
assert_eq!(
**arg,
Argument {
position: ArgumentNamed("thing"),
position_span: 2..7,
format: FormatSpec { ty: ":+", ty_span: Some(7..9), ..Default::default() },
}
);
assert_eq!(parser.line_spans, &[]);
assert!(parser.errors.is_empty());
}

View File

@@ -17,7 +17,7 @@ use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue};
use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{Span, Symbol};
use rustc_span::{Span, Symbol, sym};
use crate::Session;
use crate::config::{Cfg, CheckCfg};
@@ -192,8 +192,11 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
} else {
err.subdiagnostic(FeatureDiagnosticHelp { feature });
}
if sess.opts.unstable_opts.ui_testing {
if feature == sym::rustc_attrs {
// We're unlikely to stabilize something out of `rustc_attrs`
// without at least renaming it, so pointing out how old
// the compiler is will do little good.
} else if sess.opts.unstable_opts.ui_testing {
err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
} else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
err.subdiagnostic(suggestion);

View File

@@ -810,7 +810,8 @@ impl<'tcx> OnUnimplementedFormatString {
let mut result = Ok(());
match FormatString::parse(self.symbol, self.span, &ctx) {
let snippet = tcx.sess.source_map().span_to_snippet(self.span).ok();
match FormatString::parse(self.symbol, snippet, self.span, &ctx) {
// Warnings about format specifiers, deprecated parameters, wrong parameters etc.
// In other words we'd like to let the author know, but we can still try to format the string later
Ok(FormatString { warnings, .. }) => {
@@ -848,14 +849,13 @@ impl<'tcx> OnUnimplementedFormatString {
}
}
}
// Errors from the underlying `rustc_parse_format::Parser`
Err(errors) => {
// Error from the underlying `rustc_parse_format::Parser`
Err(e) => {
// we cannot return errors from processing the format string as hard error here
// as the diagnostic namespace guarantees that malformed input cannot cause an error
//
// if we encounter any error while processing we nevertheless want to show it as warning
// so that users are aware that something is not correct
for e in errors {
if self.is_diagnostic_namespace_variant {
if let Some(trait_def_id) = trait_def_id.as_local() {
tcx.emit_node_span_lint(
@@ -866,19 +866,13 @@ impl<'tcx> OnUnimplementedFormatString {
);
}
} else {
let reported = struct_span_code_err!(
tcx.dcx(),
self.span,
E0231,
"{}",
e.description,
)
let reported =
struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,)
.emit();
result = Err(reported);
}
}
}
}
result
}
@@ -896,7 +890,8 @@ impl<'tcx> OnUnimplementedFormatString {
Ctx::RustcOnUnimplemented { tcx, trait_def_id }
};
if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) {
// No point passing a snippet here, we already did that in `verify`
if let Ok(s) = FormatString::parse(self.symbol, None, self.span, &ctx) {
s.format(args)
} else {
// we cannot return errors from processing the format string as hard error here

View File

@@ -198,7 +198,7 @@ enum LitOrArg {
impl FilterFormatString {
fn parse(input: Symbol) -> Self {
let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format)
let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic)
.map(|p| match p {
Piece::Lit(s) => LitOrArg::Lit(s.to_owned()),
// We just ignore formatspecs here

View File

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

View File

@@ -1636,6 +1636,19 @@ fn test_chunk_by() {
assert_eq!(iter.next_back(), Some(&[1][..]));
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
assert_eq!(iter.next_back(), None);
let mut iter = slice.chunk_by(|a, b| a == b);
assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
assert_eq!(iter.next(), Some(&[3, 3][..]));
let mut iter_clone = iter.clone();
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
assert_eq!(iter.next(), Some(&[1][..]));
assert_eq!(iter.next(), Some(&[0][..]));
assert_eq!(iter.next(), None);
assert_eq!(iter_clone.next(), Some(&[2, 2, 2][..]));
assert_eq!(iter_clone.next(), Some(&[1][..]));
assert_eq!(iter_clone.next(), Some(&[0][..]));
assert_eq!(iter_clone.next(), None);
}
#[test]

View File

@@ -1847,6 +1847,8 @@ mod prim_ref {}
/// - If `T` is guaranteed to be subject to the [null pointer
/// optimization](option/index.html#representation), and `E` is an enum satisfying the following
/// requirements, then `T` and `E` are ABI-compatible. Such an enum `E` is called "option-like".
/// - The enum `E` uses the [`Rust` representation], and is not modified by the `align` or
/// `packed` representation modifiers.
/// - The enum `E` has exactly two variants.
/// - One variant has exactly one field, of type `T`.
/// - All fields of the other variant are zero-sized with 1-byte alignment.
@@ -1920,6 +1922,7 @@ mod prim_ref {}
/// [`Pointer`]: fmt::Pointer
/// [`UnwindSafe`]: panic::UnwindSafe
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
/// [`Rust` representation]: <https://doc.rust-lang.org/reference/type-layout.html#the-rust-representation>
///
/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
/// these traits are specially known to the compiler.

View File

@@ -3376,6 +3376,13 @@ where
#[stable(feature = "slice_group_by", since = "1.77.0")]
impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {}
#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")]
impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> {
fn clone(&self) -> Self {
Self { slice: self.slice, predicate: self.predicate.clone() }
}
}
#[stable(feature = "slice_group_by", since = "1.77.0")]
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@@ -891,6 +891,19 @@ impl AtomicBool {
/// Err(false));
/// assert_eq!(some_bool.load(Ordering::Relaxed), false);
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
/// [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[doc(alias = "compare_and_swap")]
@@ -973,6 +986,19 @@ impl AtomicBool {
/// }
/// }
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
/// [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[doc(alias = "compare_and_swap")]
@@ -1271,11 +1297,14 @@ impl AtomicBool {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -1338,11 +1367,14 @@ impl AtomicBool {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -1393,11 +1425,14 @@ impl AtomicBool {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -1825,6 +1860,20 @@ impl<T> AtomicPtr<T> {
/// let value = some_ptr.compare_exchange(ptr, other_ptr,
/// Ordering::SeqCst, Ordering::Relaxed);
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "ptr")]
@@ -1874,6 +1923,20 @@ impl<T> AtomicPtr<T> {
/// }
/// }
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "ptr")]
@@ -1917,11 +1980,15 @@ impl<T> AtomicPtr<T> {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
/// which is a particularly common pitfall for pointers!
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -1992,11 +2059,15 @@ impl<T> AtomicPtr<T> {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
/// which is a particularly common pitfall for pointers!
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -2057,11 +2128,15 @@ impl<T> AtomicPtr<T> {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
/// which is a particularly common pitfall for pointers!
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -2967,6 +3042,20 @@ macro_rules! atomic_int {
/// Err(10));
/// assert_eq!(some_var.load(Ordering::Relaxed), 10);
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim! This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[$stable_cxchg]
#[$cfg_cas]
@@ -3016,6 +3105,20 @@ macro_rules! atomic_int {
/// }
/// }
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[$stable_cxchg]
#[$cfg_cas]
@@ -3246,13 +3349,16 @@ macro_rules! atomic_int {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
/// and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -3309,13 +3415,16 @@ macro_rules! atomic_int {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
/// and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@@ -3367,13 +3476,17 @@ macro_rules! atomic_int {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
/// and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///

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.
This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0
-Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`.
* `-Zmiri-deterministic-floats` makes Miri's floating-point behavior fully deterministic. This means
that operations will always return the preferred NaN, imprecise operations will not have any
random error applied to them, and `min`/`max` as "maybe fused" multiply-add all behave
deterministically. Note that Miri still uses host floats for some operations, so behavior can
still differ depending on the host target and setup.
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
the program has access to host resources such as environment variables, file
systems, and randomness.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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 {
let this = self.eval_context_ref();
if !this.machine.float_nondet {
return F2::NAN;
}
/// Make the given NaN a signaling NaN.
/// Returns `None` if this would not result in a NaN.
fn make_signaling<F: Float>(f: F) -> Option<F> {
@@ -89,7 +94,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if f.is_nan() { Some(f) } else { None }
}
let this = self.eval_context_ref();
let mut rand = this.machine.rng.borrow_mut();
// Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation.
// On some targets there are more possibilities; for now we just generate those options that
@@ -118,6 +122,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F {
let this = self.eval_context_ref();
if !this.machine.float_nondet {
return a;
}
// Return one side non-deterministically.
let mut rand = this.machine.rng.borrow_mut();
if rand.random() { a } else { b }

View File

@@ -1,5 +1,7 @@
#[rustc_do_not_const_check]
//~^ ERROR this is an internal attribute that will never be stable
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable
//~| NOTE `#[rustc_do_not_const_check]` skips const-check for this function's body
const fn foo() {}
fn main() {}

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
|
LL | #[rustc_do_not_const_check]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable
= note: `#[rustc_do_not_const_check]` skips const-check for this function's body
error: aborting due to 1 previous error

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

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

View File

@@ -1,6 +1,8 @@
// check that `pattern_complexity_limit` is feature-gated
#![pattern_complexity_limit = "42"]
//~^ ERROR: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests
//~^ ERROR: use of an internal attribute [E0658]
//~| NOTE the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable
//~| NOTE: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests
fn main() {}

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
|
LL | #![pattern_complexity_limit = "42"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable
= note: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests
error: aborting due to 1 previous error

View File

@@ -1,6 +1,12 @@
// Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate.
#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable
#[rustc_variance]
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable
//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests
#[rustc_nonnull_optimization_guaranteed]
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable
//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library
//~| NOTE the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized
fn main() {}

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
|
LL | #[rustc_variance]
| ^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable
= note: the `#[rustc_variance]` attribute is used for rustc unit tests
error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable
(note that the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized)
--> $DIR/feature-gate-rustc-attrs-1.rs:4:1
error[E0658]: use of an internal attribute
--> $DIR/feature-gate-rustc-attrs-1.rs:7:1
|
LL | #[rustc_nonnull_optimization_guaranteed]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable
= note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library
= note: the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized
error: aborting due to 2 previous errors

View File

@@ -8,15 +8,19 @@ mod unknown { pub macro rustc() {} }
#[rustc::unknown]
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
//~| ERROR expected attribute, found macro `rustc::unknown`
//~| NOTE not an attribute
fn f() {}
#[unknown::rustc]
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
//~| ERROR expected attribute, found macro `unknown::rustc`
//~| NOTE not an attribute
fn g() {}
#[rustc_dummy]
//~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
//~| NOTE the `#[rustc_dummy]` attribute is used for rustc unit tests
#[rustc_unknown]
//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
//~| ERROR cannot find attribute `rustc_unknown` in this scope

View File

@@ -11,37 +11,38 @@ LL | #[rustc::unknown]
| ^^^^^^^^^^^^^^ not an attribute
error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
--> $DIR/feature-gate-rustc-attrs.rs:13:12
--> $DIR/feature-gate-rustc-attrs.rs:14:12
|
LL | #[unknown::rustc]
| ^^^^^
error: expected attribute, found macro `unknown::rustc`
--> $DIR/feature-gate-rustc-attrs.rs:13:3
--> $DIR/feature-gate-rustc-attrs.rs:14:3
|
LL | #[unknown::rustc]
| ^^^^^^^^^^^^^^ not an attribute
error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
--> $DIR/feature-gate-rustc-attrs.rs:20:3
--> $DIR/feature-gate-rustc-attrs.rs:24:3
|
LL | #[rustc_unknown]
| ^^^^^^^^^^^^^
error: cannot find attribute `rustc_unknown` in this scope
--> $DIR/feature-gate-rustc-attrs.rs:20:3
--> $DIR/feature-gate-rustc-attrs.rs:24:3
|
LL | #[rustc_unknown]
| ^^^^^^^^^^^^^
error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests and will never be stable
--> $DIR/feature-gate-rustc-attrs.rs:18:1
error[E0658]: use of an internal attribute
--> $DIR/feature-gate-rustc-attrs.rs:20:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
= note: the `#[rustc_dummy]` attribute is used for rustc unit tests
error: aborting due to 7 previous errors

View File

@@ -11,9 +11,11 @@
#![macro_export]
//~^ ERROR: `macro_export` attribute cannot be used at crate level
#![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify
#![rustc_main]
//~^ ERROR: `rustc_main` attribute cannot be used at crate level
//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
//~| ERROR: use of an internal attribute [E0658]
//~| NOTE: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
//~| NOTE: the `#[rustc_main]` attribute is used internally to specify test entry point function
#![repr()]
//~^ ERROR: `repr` attribute cannot be used at crate level
#![path = "3800"]

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
|
LL | #![rustc_main]
| ^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
= note: the `#[rustc_main]` attribute is used internally to specify test entry point function
error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
|
LL | #[inline = "2100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^
@@ -18,7 +19,7 @@ LL | #[inline = "2100"] fn f() { }
= note: `#[deny(ill_formed_attribute_input)]` on by default
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
|
LL | #[inline]
| ^^^^^^^^^
@@ -29,7 +30,7 @@ LL | | }
| |_- not a function or closure
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:1
|
LL | #[no_link]
| ^^^^^^^^^^
@@ -43,7 +44,7 @@ LL | | }
| |_- not an `extern crate` item
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1
|
LL | #[export_name = "2200"]
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +58,7 @@ LL | | }
| |_- not a free function, impl method or static
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:8
|
LL | #[repr(C)]
| ^
@@ -70,7 +71,7 @@ LL | | }
| |_- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:8
|
LL | #[repr(Rust)]
| ^^^^
@@ -83,19 +84,19 @@ LL | | }
| |_- not a struct, enum, or union
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
|
LL | #![no_link]
| ^^^^^^^^^^^ not an `extern crate` item
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
|
LL | #![export_name = "2200"]
| ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
|
LL | #![inline]
| ^^^^^^^^^^ not a function or closure
@@ -131,7 +132,7 @@ LL + #[rustc_main]
|
error: `path` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
|
LL | #![path = "3800"]
| ^^^^^^^^^^^^^^^^^
@@ -146,7 +147,7 @@ LL + #[path = "3800"]
|
error: `automatically_derived` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1
|
LL | #![automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -161,7 +162,7 @@ LL + #[automatically_derived]
|
error: `repr` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
|
LL | #![repr()]
| ^^^^^^^^^^
@@ -176,139 +177,139 @@ LL + #[repr()]
|
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17
|
LL | mod inner { #![inline] }
| ------------^^^^^^^^^^-- not a function or closure
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5
|
LL | #[inline] struct S;
| ^^^^^^^^^ --------- not a function or closure
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:5
|
LL | #[inline] type T = S;
| ^^^^^^^^^ ----------- not a function or closure
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:5
|
LL | #[inline] impl S { }
| ^^^^^^^^^ ---------- not a function or closure
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:17
|
LL | mod inner { #![no_link] }
| ------------^^^^^^^^^^^-- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:74:5
|
LL | #[no_link] fn f() { }
| ^^^^^^^^^^ ---------- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5
|
LL | #[no_link] struct S;
| ^^^^^^^^^^ --------- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5
|
LL | #[no_link]type T = S;
| ^^^^^^^^^^----------- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5
|
LL | #[no_link] impl S { }
| ^^^^^^^^^^ ---------- not an `extern crate` item
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17
|
LL | mod inner { #![export_name="2200"] }
| ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5
|
LL | #[export_name = "2200"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5
|
LL | #[export_name = "2200"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5
|
LL | #[export_name = "2200"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:9
|
LL | #[export_name = "2200"] fn foo();
| ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
error: attribute should be applied to a free function, impl method or static
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:9
|
LL | #[export_name = "2200"] fn bar() {}
| ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:25
|
LL | mod inner { #![repr(C)] }
| --------------------^---- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:12
|
LL | #[repr(C)] fn f() { }
| ^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12
|
LL | #[repr(C)] type T = S;
| ^ ----------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12
|
LL | #[repr(C)] impl S { }
| ^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:153:25
|
LL | mod inner { #![repr(Rust)] }
| --------------------^^^^---- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:157:12
|
LL | #[repr(Rust)] fn f() { }
| ^^^^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:163:12
|
LL | #[repr(Rust)] type T = S;
| ^^^^ ----------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:167:12
|
LL | #[repr(Rust)] impl S { }
| ^^^^ ---------- not a struct, enum, or union

View File

@@ -2,11 +2,15 @@
#![allow(internal_features)]
#[rustc_force_inline]
//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined
pub fn bare() {
}
#[rustc_force_inline = "the test requires it"]
//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined
pub fn justified() {
}

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
|
LL | #[rustc_force_inline]
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
= note: `#[rustc_force_inline]` forces a free function to be inlined
error[E0658]: #[rustc_force_inline] forces a free function to be inlined
--> $DIR/gate.rs:9:1
error[E0658]: use of an internal attribute
--> $DIR/gate.rs:11:1
|
LL | #[rustc_force_inline = "the test requires it"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
= note: `#[rustc_force_inline]` forces a free function to be inlined
error: aborting due to 2 previous errors

View File

@@ -1,8 +1,9 @@
// Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate.
#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
//~^ ERROR this is an internal attribute that will never be stable
trait Foo<Bar>
{}
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable
//~| NOTE see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute
trait Foo<Bar> {}
fn main() {}

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
|
LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable
= note: see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute
error: aborting due to 1 previous error

View File

@@ -1,5 +1,7 @@
#[rustc_doc_primitive = "usize"]
//~^ ERROR `rustc_doc_primitive` is a rustc internal attribute
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable
//~| NOTE the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types
/// Some docs
mod usize {}

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
|
LL | #[rustc_doc_primitive = "usize"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable
= note: the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types
error: aborting due to 1 previous error

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;
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
|
LL | #[rustc_diagnostic_item = "foomp"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes
error: aborting due to 1 previous error

View File

@@ -1,5 +1,7 @@
#[rustc_must_implement_one_of(eq, neq)]
//~^ ERROR the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
//~^ ERROR use of an internal attribute [E0658]
//~| NOTE the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable
//~| NOTE the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization
trait Equal {
fn eq(&self, other: &Self) -> bool {
!self.neq(other)

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
|
LL | #[rustc_must_implement_one_of(eq, neq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable
= note: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization
error: aborting due to 1 previous error