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