Auto merge of #149646 - matthiaskrgr:rollup-jbfeow8, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#147224 (Emscripten: Turn wasm-eh on by default)
 - rust-lang/rust#149405 (Recover on misspelled item keyword)
 - rust-lang/rust#149443 (Tidying up UI tests [6/N])
 - rust-lang/rust#149524 (Move attribute safety checking to attribute parsing)
 - rust-lang/rust#149593 (powf, powi: point out SNaN non-determinism)
 - rust-lang/rust#149605 (Use branch name instead of HEAD when unshallowing)
 - rust-lang/rust#149612 (Apply the `bors` environment also to the `outcome` job)
 - rust-lang/rust#149623 (Don't require a normal tool build of clippy/rustfmt when running their test steps)
 - rust-lang/rust#149627 (Point to the item that is incorrectly annotated with `#[diagnostic::on_const]`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-12-04 22:04:03 +00:00
commit 3e2dbcdd3a
86 changed files with 645 additions and 447 deletions

View file

@ -313,6 +313,7 @@ jobs:
needs: [ calculate_matrix, job ]
# !cancelled() executes the job regardless of whether the previous jobs passed or failed
if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }}
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto')) && 'bors') || '' }}
steps:
- name: checkout the source code
uses: actions/checkout@v5

View file

@ -1075,7 +1075,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_attribute(&mut self, attr: &Attribute) {
validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id);
validate_attr::check_attr(&self.sess.psess, attr);
}
fn visit_ty(&mut self, ty: &'a Ty) {

View file

@ -1,3 +1,5 @@
use std::convert::identity;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token};
@ -353,7 +355,7 @@ pub fn parse_cfg_attr(
span,
attr_span: cfg_attr.span,
template: CFG_ATTR_TEMPLATE,
path: AttrPath::from_ast(&cfg_attr.get_normal_item().path),
path: AttrPath::from_ast(&cfg_attr.get_normal_item().path, identity),
description: ParsedDescription::Attribute,
reason,
suggestions: CFG_ATTR_TEMPLATE
@ -398,6 +400,7 @@ fn parse_cfg_attr_internal<'a>(
.into_boxed_slice(),
span: attribute.span,
},
Some(attribute.get_normal_item().unsafety),
ParsedDescription::Attribute,
pred_span,
CRATE_NODE_ID,

View file

@ -63,6 +63,7 @@ pub fn parse_cfg_select(
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
span: cfg_span,
},
None,
ParsedDescription::Macro,
cfg_span,
lint_node_id,

View file

@ -1,7 +1,7 @@
use std::borrow::Cow;
use rustc_ast as ast;
use rustc_ast::{AttrStyle, NodeId};
use rustc_ast::{AttrStyle, NodeId, Safety};
use rustc_errors::DiagCtxtHandle;
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::AttributeKind;
@ -146,6 +146,7 @@ impl<'sess> AttributeParser<'sess, Early> {
normal_attr.item.span(),
attr.style,
path.get_attribute_path(),
Some(normal_attr.item.unsafety),
ParsedDescription::Attribute,
target_span,
target_node_id,
@ -165,6 +166,7 @@ impl<'sess> AttributeParser<'sess, Early> {
inner_span: Span,
attr_style: AttrStyle,
attr_path: AttrPath,
attr_safety: Option<Safety>,
parsed_description: ParsedDescription,
target_span: Span,
target_node_id: NodeId,
@ -181,14 +183,24 @@ impl<'sess> AttributeParser<'sess, Early> {
sess,
stage: Early { emit_errors },
};
let mut emit_lint = |lint| {
crate::lints::emit_attribute_lint(&lint, sess);
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(
&attr_path,
inner_span,
safety,
&mut emit_lint,
target_node_id,
)
}
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
shared: SharedContext {
cx: &mut parser,
target_span,
target_id: target_node_id,
emit_lint: &mut |lint| {
crate::lints::emit_attribute_lint(&lint, sess);
},
emit_lint: &mut emit_lint,
},
attr_span,
inner_span,
@ -288,6 +300,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
// }
ast::AttrKind::Normal(n) => {
attr_paths.push(PathParser(Cow::Borrowed(&n.item.path)));
let attr_path = AttrPath::from_ast(&n.item.path, lower_span);
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
&mut emit_lint,
target_id,
);
let parts =
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
@ -301,7 +322,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
) else {
continue;
};
let path = parser.path();
let args = parser.args();
for accept in accepts {
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
@ -312,11 +332,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
emit_lint: &mut emit_lint,
},
attr_span: lower_span(attr.span),
inner_span: lower_span(attr.get_normal_item().span()),
inner_span: lower_span(n.item.span()),
attr_style: attr.style,
parsed_description: ParsedDescription::Attribute,
template: &accept.template,
attr_path: path.get_attribute_path(),
attr_path: attr_path.clone(),
};
(accept.accept_fn)(&mut cx, args);
@ -341,7 +361,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
// );
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
path: AttrPath::from_ast(&n.item.path),
path: attr_path.clone(),
args: self.lower_attr_args(&n.item.args, lower_span),
id: HashIgnoredAttrId { attr_id: attr.id },
style: attr.style,

View file

@ -98,6 +98,7 @@ mod interface;
pub mod parser;
mod lints;
mod safety;
mod session_diagnostics;
mod target_checking;
pub mod validate_attr;

View file

@ -98,5 +98,17 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi
},
)
}
&AttributeLintKind::UnsafeAttrOutsideUnsafe {
attribute_name_span,
sugg_spans: (left, right),
} => lint_emitter.emit_node_span_lint(
rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE,
*id,
*span,
session_diagnostics::UnsafeAttrOutsideUnsafeLint {
span: attribute_name_span,
suggestion: session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right },
},
),
}
}

View file

@ -0,0 +1,116 @@
use rustc_ast::Safety;
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir::AttrPath;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_span::{Span, sym};
use crate::context::Stage;
use crate::{AttributeParser, ShouldEmit};
impl<'sess, S: Stage> AttributeParser<'sess, S> {
pub fn check_attribute_safety(
&mut self,
attr_path: &AttrPath,
attr_span: Span,
attr_safety: Safety,
emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
target_id: S::Id,
) {
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
return;
}
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name);
if let Some(name) = name
&& [sym::cfg_trace, sym::cfg_attr_trace].contains(&name)
{
return;
}
// FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP`
let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
match (builtin_attr_safety, attr_safety) {
// - Unsafe builtin attribute
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
// OK
}
// - Unsafe builtin attribute
// - User did not write `#[unsafe(..)]`
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
let path_span = attr_path.span;
// If the `attr_item`'s span is not from a macro, then just suggest
// wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
// `unsafe(`, `)` right after and right before the opening and closing
// square bracket respectively.
let diag_span = attr_span;
// Attributes can be safe in earlier editions, and become unsafe in later ones.
//
// Use the span of the attribute's name to determine the edition: the span of the
// attribute as a whole may be inaccurate if it was emitted by a macro.
//
// See https://github.com/rust-lang/rust/issues/142182.
let emit_error = match unsafe_since {
None => true,
Some(unsafe_since) => path_span.edition() >= unsafe_since,
};
if emit_error {
self.stage.emit_err(
self.sess,
crate::session_diagnostics::UnsafeAttrOutsideUnsafe {
span: path_span,
suggestion:
crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion {
left: diag_span.shrink_to_lo(),
right: diag_span.shrink_to_hi(),
},
},
);
} else {
emit_lint(AttributeLint {
id: target_id,
span: path_span,
kind: AttributeLintKind::UnsafeAttrOutsideUnsafe {
attribute_name_span: path_span,
sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),
},
})
}
}
// - Normal builtin attribute
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
self.stage.emit_err(
self.sess,
crate::session_diagnostics::InvalidAttrUnsafe {
span: unsafe_span,
name: attr_path.clone(),
},
);
}
// - Normal builtin attribute
// - No explicit `#[unsafe(..)]` written.
(None | Some(AttributeSafety::Normal), Safety::Default) => {
// OK
}
(
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
Safety::Safe(..),
) => {
self.sess.dcx().span_delayed_bug(
attr_span,
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
);
}
}
}
}

View file

@ -1,6 +1,6 @@
use std::num::IntErrorKind;
use rustc_ast::{self as ast, Path};
use rustc_ast::{self as ast};
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
@ -790,7 +790,7 @@ pub(crate) struct InvalidAttrUnsafe {
#[primary_span]
#[label]
pub span: Span,
pub name: Path,
pub name: AttrPath,
}
#[derive(Diagnostic)]
@ -803,6 +803,15 @@ pub(crate) struct UnsafeAttrOutsideUnsafe {
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
}
#[derive(LintDiagnostic)]
#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
pub(crate) struct UnsafeAttrOutsideUnsafeLint {
#[label]
pub span: Span,
#[subdiagnostic]
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
attr_parsing_unsafe_attr_outside_unsafe_suggestion,

View file

@ -1,25 +1,26 @@
//! Meta-syntax validation logic of attributes for post-expansion.
use std::convert::identity;
use std::slice;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId,
Path, Safety,
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety,
};
use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult};
use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_errors::{Applicability, FatalError, PResult};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_hir::AttrPath;
use rustc_parse::parse_in;
use rustc_session::errors::report_lit_error;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::ParseSess;
use rustc_span::{Span, Symbol, sym};
use crate::{AttributeParser, Late, session_diagnostics as errors};
pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
{
return;
@ -27,9 +28,6 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
check_attribute_safety(psess, builtin_attr_safety, attr, id);
// Check input tokens for built-in and key-value attributes.
match builtin_attr_info {
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
@ -150,101 +148,6 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
}
}
pub fn check_attribute_safety(
psess: &ParseSess,
builtin_attr_safety: Option<AttributeSafety>,
attr: &Attribute,
id: NodeId,
) {
let attr_item = attr.get_normal_item();
match (builtin_attr_safety, attr_item.unsafety) {
// - Unsafe builtin attribute
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
// OK
}
// - Unsafe builtin attribute
// - User did not write `#[unsafe(..)]`
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
let path_span = attr_item.path.span;
// If the `attr_item`'s span is not from a macro, then just suggest
// wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
// `unsafe(`, `)` right after and right before the opening and closing
// square bracket respectively.
let diag_span = attr_item.span();
// Attributes can be safe in earlier editions, and become unsafe in later ones.
//
// Use the span of the attribute's name to determine the edition: the span of the
// attribute as a whole may be inaccurate if it was emitted by a macro.
//
// See https://github.com/rust-lang/rust/issues/142182.
let emit_error = match unsafe_since {
None => true,
Some(unsafe_since) => path_span.edition() >= unsafe_since,
};
if emit_error {
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
span: path_span,
suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {
left: diag_span.shrink_to_lo(),
right: diag_span.shrink_to_hi(),
},
});
} else {
psess.buffer_lint(
UNSAFE_ATTR_OUTSIDE_UNSAFE,
path_span,
id,
BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
attribute_name_span: path_span,
sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),
},
);
}
}
// - Normal builtin attribute
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
span: unsafe_span,
name: attr_item.path.clone(),
});
}
// - Normal builtin attribute
// - No explicit `#[unsafe(..)]` written.
(None | Some(AttributeSafety::Normal), Safety::Default) => {
// OK
}
(
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
Safety::Safe(..),
) => {
psess.dcx().span_delayed_bug(
attr_item.span(),
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
);
}
}
}
// Called by `check_builtin_meta_item` and code that manually denies
// `unsafe(...)` in `cfg`
pub fn deny_builtin_meta_unsafety(diag: DiagCtxtHandle<'_>, unsafety: Safety, name: &Path) {
// This only supports denying unsafety right now - making builtin attributes
// support unsafety will requite us to thread the actual `Attribute` through
// for the nice diagnostics.
if let Safety::Unsafe(unsafe_span) = unsafety {
diag.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: name.clone() });
}
}
pub fn check_builtin_meta_item(
psess: &ParseSess,
meta: &MetaItem,
@ -258,8 +161,11 @@ pub fn check_builtin_meta_item(
emit_malformed_attribute(psess, style, meta.span, name, template);
}
if deny_unsafety {
deny_builtin_meta_unsafety(psess.dcx(), meta.unsafety, &meta.path);
if deny_unsafety && let Safety::Unsafe(unsafe_span) = meta.unsafety {
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
span: unsafe_span,
name: AttrPath::from_ast(&meta.path, identity),
});
}
}

View file

@ -54,6 +54,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
span,
AttrStyle::Inner,
AttrPath { segments: vec![Ident::from_str("cfg")].into_boxed_slice(), span },
None,
ParsedDescription::Macro,
span,
cx.current_expansion.lint_node_id,

View file

@ -11,15 +11,13 @@ use rustc_ast::{
NodeId, NormalAttr,
};
use rustc_attr_parsing as attr;
use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety;
use rustc_attr_parsing::{
AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
validate_attr,
};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_feature::{
ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features,
REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES,
UNSTABLE_LANG_FEATURES,
};
use rustc_session::Session;
use rustc_session::parse::feature_err;
@ -291,13 +289,6 @@ impl<'a> StripUnconfigured<'a> {
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
validate_attr::check_attribute_safety(
&self.sess.psess,
Some(AttributeSafety::Normal),
&cfg_attr,
ast::CRATE_NODE_ID,
);
// A trace attribute left in AST in place of the original `cfg_attr` attribute.
// It can later be used by lints or other diagnostics.
let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace);
@ -421,13 +412,6 @@ impl<'a> StripUnconfigured<'a> {
node: NodeId,
emit_errors: ShouldEmit,
) -> EvalConfigResult {
// Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check
deny_builtin_meta_unsafety(
self.sess.dcx(),
attr.get_normal_item().unsafety,
&rustc_ast::Path::from_ident(attr.ident().unwrap()),
);
let Some(cfg) = AttributeParser::parse_single(
self.sess,
attr,

View file

@ -2158,11 +2158,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
let mut span: Option<Span> = None;
while let Some(attr) = attrs.next() {
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
validate_attr::check_attr(
&self.cx.sess.psess,
attr,
self.cx.current_expansion.lint_node_id,
);
validate_attr::check_attr(&self.cx.sess.psess, attr);
AttributeParser::parse_limited_all(
self.cx.sess,
slice::from_ref(attr),

View file

@ -1193,10 +1193,15 @@ impl IntoDiagArg for AttrPath {
}
impl AttrPath {
pub fn from_ast(path: &ast::Path) -> Self {
pub fn from_ast(path: &ast::Path, lower_span: impl Copy + Fn(Span) -> Span) -> Self {
AttrPath {
segments: path.segments.iter().map(|i| i.ident).collect::<Vec<_>>().into_boxed_slice(),
span: path.span,
segments: path
.segments
.iter()
.map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) })
.collect::<Vec<_>>()
.into_boxed_slice(),
span: lower_span(path.span),
}
}
}

View file

@ -62,4 +62,8 @@ pub enum AttributeLintKind {
target: Target,
target_span: Span,
},
UnsafeAttrOutsideUnsafe {
attribute_name_span: Span,
sugg_spans: (Span, Span),
},
}

View file

@ -798,7 +798,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(embed_metadata, false);
tracked!(embed_source, true);
tracked!(emit_thin_lto, false);
tracked!(emscripten_wasm_eh, true);
tracked!(emscripten_wasm_eh, false);
tracked!(export_executable_symbols, true);
tracked!(fewer_names, Some(true));
tracked!(fixed_x18, true);

View file

@ -890,10 +890,6 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
.label = usage of unsafe attribute
lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
lint_untranslatable_diag = diagnostics should be created using translatable messages

View file

@ -283,16 +283,6 @@ pub fn decorate_builtin_lint(
BuiltinLintDiag::UnusedQualifications { removal_span } => {
lints::UnusedQualifications { removal_span }.decorate_lint(diag);
}
BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
attribute_name_span,
sugg_spans: (left, right),
} => {
lints::UnsafeAttrOutsideUnsafe {
span: attribute_name_span,
suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right },
}
.decorate_lint(diag);
}
BuiltinLintDiag::AssociatedConstElidedLifetime {
elided,
span: lt_span,

View file

@ -2880,27 +2880,6 @@ pub(crate) struct AssociatedConstElidedLifetime {
pub lifetimes_in_scope: MultiSpan,
}
#[derive(LintDiagnostic)]
#[diag(lint_unsafe_attr_outside_unsafe)]
pub(crate) struct UnsafeAttrOutsideUnsafe {
#[label]
pub span: Span,
#[subdiagnostic]
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
lint_unsafe_attr_outside_unsafe_suggestion,
applicability = "machine-applicable"
)]
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
#[suggestion_part(code = "unsafe(")]
pub left: Span,
#[suggestion_part(code = ")")]
pub right: Span,
}
#[derive(LintDiagnostic)]
#[diag(lint_static_mut_refs_lint)]
pub(crate) struct RefOfMutStatic<'a> {

View file

@ -687,10 +687,6 @@ pub enum BuiltinLintDiag {
/// The span of the unnecessarily-qualified path to remove.
removal_span: Span,
},
UnsafeAttrOutsideUnsafe {
attribute_name_span: Span,
sugg_spans: (Span, Span),
},
AssociatedConstElidedLifetime {
elided: bool,
span: Span,

View file

@ -228,8 +228,8 @@ impl<'a> Parser<'a> {
body,
define_opaque: None,
}))
} else if self.eat_keyword(exp!(Extern)) {
if self.eat_keyword(exp!(Crate)) {
} else if self.eat_keyword_case(exp!(Extern), case) {
if self.eat_keyword_case(exp!(Crate), case) {
// EXTERN CRATE
self.parse_item_extern_crate()?
} else {
@ -241,19 +241,17 @@ impl<'a> Parser<'a> {
let safety = self.parse_safety(Case::Sensitive);
self.expect_keyword(exp!(Extern))?;
self.parse_item_foreign_mod(attrs, safety)?
} else if self.is_static_global() {
let safety = self.parse_safety(Case::Sensitive);
} else if let Some(safety) = self.parse_global_static_front_matter(case) {
// STATIC ITEM
self.bump(); // `static`
let mutability = self.parse_mutability();
self.parse_static_item(safety, mutability)?
} else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() {
} else if self.check_keyword_case(exp!(Trait), case) || self.check_trait_front_matter() {
// TRAIT ITEM
self.parse_item_trait(attrs, lo)?
} else if self.check_impl_frontmatter() {
// IMPL ITEM
self.parse_item_impl(attrs, def_())?
} else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
} else if let Const::Yes(const_span) = self.parse_constness(case) {
// CONST ITEM
self.recover_const_mut(const_span);
self.recover_missing_kw_before_item()?;
@ -268,18 +266,18 @@ impl<'a> Parser<'a> {
}))
} else if self.is_reuse_path_item() {
self.parse_item_delegation()?
} else if self.check_keyword(exp!(Mod))
|| self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Mod])
} else if self.check_keyword_case(exp!(Mod), case)
|| self.check_keyword_case(exp!(Unsafe), case) && self.is_keyword_ahead(1, &[kw::Mod])
{
// MODULE ITEM
self.parse_item_mod(attrs)?
} else if self.eat_keyword(exp!(Type)) {
} else if self.eat_keyword_case(exp!(Type), case) {
// TYPE ITEM
self.parse_type_alias(def_())?
} else if self.eat_keyword(exp!(Enum)) {
} else if self.eat_keyword_case(exp!(Enum), case) {
// ENUM ITEM
self.parse_item_enum()?
} else if self.eat_keyword(exp!(Struct)) {
} else if self.eat_keyword_case(exp!(Struct), case) {
// STRUCT ITEM
self.parse_item_struct()?
} else if self.is_kw_followed_by_ident(kw::Union) {
@ -289,7 +287,7 @@ impl<'a> Parser<'a> {
} else if self.is_builtin() {
// BUILTIN# ITEM
return self.parse_item_builtin();
} else if self.eat_keyword(exp!(Macro)) {
} else if self.eat_keyword_case(exp!(Macro), case) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
} else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
@ -1324,19 +1322,28 @@ impl<'a> Parser<'a> {
== Some(true)
}
fn is_static_global(&mut self) -> bool {
if self.check_keyword(exp!(Static)) {
fn parse_global_static_front_matter(&mut self, case: Case) -> Option<Safety> {
let is_global_static = if self.check_keyword_case(exp!(Static), case) {
// Check if this could be a closure.
!self.look_ahead(1, |token| {
if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) {
if token.is_keyword_case(kw::Move, case) || token.is_keyword_case(kw::Use, case) {
return true;
}
matches!(token.kind, token::Or | token::OrOr)
})
} else {
// `$qual static`
(self.check_keyword(exp!(Unsafe)) || self.check_keyword(exp!(Safe)))
&& self.look_ahead(1, |t| t.is_keyword(kw::Static))
(self.check_keyword_case(exp!(Unsafe), case)
|| self.check_keyword_case(exp!(Safe), case))
&& self.look_ahead(1, |t| t.is_keyword_case(kw::Static, case))
};
if is_global_static {
let safety = self.parse_safety(case);
let _ = self.eat_keyword_case(exp!(Static), case);
Some(safety)
} else {
None
}
}

View file

@ -98,6 +98,7 @@ passes_deprecated_attribute =
passes_diagnostic_diagnostic_on_const_only_for_trait_impls =
`#[diagnostic::on_const]` can only be applied to trait impls
.label = not a trait impl
passes_diagnostic_diagnostic_on_unimplemented_only_for_traits =
`#[diagnostic::on_unimplemented]` can only be applied to trait definitions

View file

@ -57,7 +57,10 @@ struct DiagnosticOnUnimplementedOnlyForTraits;
#[derive(LintDiagnostic)]
#[diag(passes_diagnostic_diagnostic_on_const_only_for_trait_impls)]
struct DiagnosticOnConstOnlyForTraitImpls;
struct DiagnosticOnConstOnlyForTraitImpls {
#[label]
item_span: Span,
}
fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
match impl_item.kind {
@ -541,11 +544,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
ItemLike::ForeignItem => {}
}
}
let item_span = self.tcx.hir_span(hir_id);
self.tcx.emit_node_span_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
DiagnosticOnConstOnlyForTraitImpls,
DiagnosticOnConstOnlyForTraitImpls { item_span },
);
}

View file

@ -2338,7 +2338,7 @@ options! {
"emit a section containing stack size metadata (default: no)"),
emit_thin_lto: bool = (true, parse_bool, [TRACKED],
"emit the bc module with thin LTO info (default: yes)"),
emscripten_wasm_eh: bool = (false, parse_bool, [TRACKED],
emscripten_wasm_eh: bool = (true, parse_bool, [TRACKED],
"Use WebAssembly error handling for wasm32-unknown-emscripten"),
enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
"enforce the type length limit when monomorphizing instances in codegen"),

View file

@ -1800,6 +1800,11 @@ impl f128 {
/// It might have a different sequence of rounding operations than `powf`,
/// so the results are not guaranteed to agree.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f128::powi(f128::NAN, 0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform,

View file

@ -1775,6 +1775,11 @@ impl f16 {
/// It might have a different sequence of rounding operations than `powf`,
/// so the results are not guaranteed to agree.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f16::powi(f16::NAN, 0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform,

View file

@ -19,6 +19,11 @@ use crate::sys::cmath;
impl f128 {
/// Raises a number to a floating point power.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f128::powf(f128::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform,

View file

@ -19,6 +19,11 @@ use crate::sys::cmath;
impl f16 {
/// Raises a number to a floating point power.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f16::powf(f16::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform,

View file

@ -295,6 +295,11 @@ impl f32 {
/// It might have a different sequence of rounding operations than `powf`,
/// so the results are not guaranteed to agree.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f32::powi(f32::NAN, 0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
@ -320,6 +325,11 @@ impl f32 {
/// Raises a number to a floating point power.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f32::powf(f32::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and

View file

@ -295,6 +295,11 @@ impl f64 {
/// It might have a different sequence of rounding operations than `powf`,
/// so the results are not guaranteed to agree.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f64::powi(f64::NAN, 0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
@ -320,6 +325,11 @@ impl f64 {
/// Raises a number to a floating point power.
///
/// Note that this function is special in that it can return non-NaN results for NaN inputs. For
/// example, `f64::powf(f64::NAN, 0.0)` returns `1.0`. However, if an input is a *signaling*
/// NaN, then the result is non-deterministically either a NaN or the result that the
/// corresponding quiet NaN would produce.
///
/// # Unspecified precision
///
/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and

View file

@ -524,8 +524,7 @@ impl Step for Rustfmt {
/// Runs `cargo test` for rustfmt.
fn run(self, builder: &Builder<'_>) {
let tool_result = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
let build_compiler = tool_result.build_compiler;
let build_compiler = self.compilers.build_compiler();
let target = self.compilers.target();
let mut cargo = tool::prepare_tool_cargo(
@ -869,11 +868,9 @@ impl Step for Clippy {
// We need to carefully distinguish the compiler that builds clippy, and the compiler
// that is linked into the clippy being tested. `target_compiler` is the latter,
// and it must also be used by clippy's test runner to build tests and their dependencies.
let compilers = self.compilers;
let target_compiler = compilers.target_compiler();
let target_compiler = self.compilers.target_compiler();
let build_compiler = self.compilers.build_compiler();
let tool_result = builder.ensure(tool::Clippy::from_compilers(compilers));
let build_compiler = tool_result.build_compiler;
let mut cargo = tool::prepare_tool_cargo(
builder,
build_compiler,

View file

@ -17,7 +17,7 @@ ci_dir=$(cd $(dirname $0) && pwd)/..
# On the beta channel we'll be automatically calculating the prerelease version
# via the git history, so unshallow our shallow clone from CI.
if [ "$(releaseChannel)" = "beta" ]; then
git fetch origin --unshallow beta HEAD
git fetch origin --unshallow beta main
fi
function fetch_github_commit_archive {

View file

@ -95,10 +95,11 @@ This target can be cross-compiled from any host.
## Emscripten ABI Compatibility
The Emscripten compiler toolchain does not follow a semantic versioning scheme
that clearly indicates when breaking changes to the ABI can be made. Additionally,
Emscripten offers many different ABIs even for a single version of Emscripten
depending on the linker flags used, e.g. `-fexceptions` and `-sWASM_BIGINT`. If
the ABIs mismatch, your code may exhibit undefined behaviour.
that clearly indicates when breaking changes to the ABI can be made.
Additionally, Emscripten offers many different ABIs even for a single version of
Emscripten depending on the linker flags used, e.g. `-fwasm-exceptions` and
`-sWASM_BIGINT`. If the ABIs do not match, your code may exhibit undefined
behaviour.
To ensure that the ABIs of your Rust code, of the Rust standard library, and of
other code compiled for Emscripten all match, you should rebuild the Rust standard
@ -158,9 +159,9 @@ features can be disabled, and how Rust code can be conditionally compiled based
which features are enabled.
Note that Rust code compiled for `wasm32-unknown-emscripten` currently enables
`-fexceptions` (JS exceptions) by default unless the Rust code is compiled with
`-Cpanic=abort`. `-fwasm-exceptions` (WASM exceptions) is not yet currently supported,
see <https://github.com/rust-lang/rust/issues/112195>.
`-fwasm-exceptions` (legacy WASM exceptions) by default unless the Rust code is
compiled with `-Cpanic=abort`. It is possible to use JS exceptions by passing
the flag ``-Z emscripten-wasm-eh=false`` but this will be removed in the future.
Please refer to the [Emscripten ABI compatibility](#emscripten-abi-compatibility)
section to ensure that the features that are enabled do not cause an ABI mismatch

View file

@ -272,8 +272,9 @@ where
("pow", [base, exp]) if *base == one => {
let rng = this.machine.rng.get_mut();
// SNaN exponents get special treatment: they might return 1, or a NaN.
// This is non-deterministic because LLVM can treat SNaN as QNaN, and because
// implementation behavior differs between glibc and musl.
let return_nan = exp.is_signaling() && this.machine.float_nondet && rng.random();
// Handle both the musl and glibc cases non-deterministically.
if return_nan { this.generate_nan(args) } else { one }
}
@ -281,8 +282,9 @@ where
("pow", [base, exp]) if exp.is_zero() => {
let rng = this.machine.rng.get_mut();
// SNaN bases get special treatment: they might return 1, or a NaN.
// This is non-deterministic because LLVM can treat SNaN as QNaN, and because
// implementation behavior differs between glibc and musl.
let return_nan = base.is_signaling() && this.machine.float_nondet && rng.random();
// Handle both the musl and glibc cases non-deterministically.
if return_nan { this.generate_nan(args) } else { one }
}
@ -306,10 +308,9 @@ where
0 => {
let one = IeeeFloat::<S>::one();
let rng = ecx.machine.rng.get_mut();
let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
// For SNaN treatment, we are consistent with `powf`above.
// (We wouldn't have two, unlike powf all implementations seem to agree for powi,
// but for now we are maximally conservative.)
// SNaN bases get special treatment: they might return 1, or a NaN.
// This is non-deterministic because LLVM can treat SNaN as QNaN.
let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random();
Some(if return_nan { ecx.generate_nan(&[base]) } else { one })
}

View file

@ -1014,7 +1014,6 @@ ui/for-loop-while/issue-1257.rs
ui/for-loop-while/issue-2216.rs
ui/for-loop-while/issue-51345.rs
ui/for-loop-while/issue-69841.rs
ui/for/issue-20605.rs
ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs
ui/foreign/issue-91370-foreign-fn-block-impl.rs
ui/foreign/issue-99276-same-type-lifetimes.rs

View file

@ -1,4 +1,4 @@
//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten
//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -Z emscripten-wasm-eh=false
//@ needs-llvm-components: webassembly
// Emscripten has its own unique implementation of catch_unwind (in `codegen_emcc_try`),

View file

@ -279,7 +279,7 @@ pub fn no_mangle() {}
#[rustc_clean(cfg = "cfail3")]
#[rustc_clean(cfg = "cfail5")]
#[rustc_clean(cfg = "cfail6")]
#[no_mangle]
#[unsafe(no_mangle)]
pub fn no_mangle() {}
// Linkage ---------------------------------------------------------------------

View file

@ -5,6 +5,7 @@
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.
//@ edition: 2024
//@ build-pass (FIXME(62277): could be check-pass?)
//@ revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6
//@ compile-flags: -Z query-dep-graph -O
@ -649,7 +650,7 @@ impl Foo {
//--------------------------
//--------------------------
//--------------------------
//----------
//------------------
pub fn add_no_mangle_to_method(&self) { }
}
@ -663,7 +664,7 @@ impl Foo {
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
#[no_mangle]
#[unsafe(no_mangle)]
pub fn add_no_mangle_to_method(&self) { }
}

View file

@ -66,7 +66,7 @@ static STATIC_NO_MANGLE: u8 = 0;
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
#[no_mangle]
#[unsafe(no_mangle)]
static STATIC_NO_MANGLE: u8 = 0;

View file

@ -569,7 +569,7 @@ impl AddNoMangleToMethod for Foo {
// -------------------------
// -------------------------
// -------------------------
// ---------
// -----------------
fn add_no_mangle_to_method(&self) { }
}
@ -583,7 +583,7 @@ impl AddNoMangleToMethod for Foo {
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
#[no_mangle]
#[unsafe(no_mangle)]
fn add_no_mangle_to_method(&self) { }
}

View file

@ -573,12 +573,6 @@ Exercises the `format!` macro.
A broad category of tests on functions.
## `tests/ui/for/`: `for` keyword
Tests on the `for` keyword and some of its associated errors, such as attempting to write the faulty pattern `for _ in 0..1 {} else {}`.
**FIXME**: Should be merged with `ui/for-loop-while`.
## `tests/ui/force-inlining/`: `#[rustc_force_inline]`
Tests for `#[rustc_force_inline]`, which will force a function to always be labelled as inline by the compiler (it will be inserted at the point of its call instead of being used as a normal function call.) If the compiler is unable to inline the function, an error will be reported. See <https://github.com/rust-lang/rust/pull/134082>.
@ -1521,10 +1515,6 @@ Tests on `enum` variants.
**FIXME**: Contains a single test described as "Check that rustc accepts various version info flags.", should be rehomed.
## `tests/ui/warnings/`
**FIXME**: Contains a single test on non-explicit paths (`::one()`). Should be rehomed probably to `tests/ui/resolve/`.
## `tests/ui/wasm/`
These tests target the `wasm32` architecture specifically. They are usually regression tests for WASM-specific bugs which were observed in the past.

View file

@ -9,6 +9,12 @@ help: escape `unsafe` to use it as an identifier
LL | #[unsafe(r#unsafe(no_mangle))]
| ++
error: cannot find attribute `r#unsafe` in this scope
--> $DIR/double-unsafe-attributes.rs:1:10
|
LL | #[unsafe(unsafe(no_mangle))]
| ^^^^^^
error: `r#unsafe` is not an unsafe attribute
--> $DIR/double-unsafe-attributes.rs:1:3
|
@ -17,11 +23,5 @@ LL | #[unsafe(unsafe(no_mangle))]
|
= note: extraneous unsafe is not allowed in attributes
error: cannot find attribute `r#unsafe` in this scope
--> $DIR/double-unsafe-attributes.rs:1:10
|
LL | #[unsafe(unsafe(no_mangle))]
| ^^^^^^
error: aborting due to 3 previous errors

View file

@ -12,46 +12,6 @@ LL | #[unsafe(allow(unsafe(dead_code)))]
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `proc_macro` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:1:3
|
LL | #[unsafe(proc_macro)]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: `proc_macro_derive` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:7:3
|
LL | #[unsafe(proc_macro_derive(Foo))]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: `proc_macro_attribute` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:18:3
|
LL | #[unsafe(proc_macro_attribute)]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:23:3
|
LL | #[unsafe(allow(dead_code))]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:27:3
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: expected identifier, found keyword `unsafe`
--> $DIR/proc-unsafe-attributes.rs:27:16
|
@ -103,6 +63,22 @@ LL | #[unsafe(allow(unsafe(dead_code)))]
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `proc_macro` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:1:3
|
LL | #[unsafe(proc_macro)]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: `proc_macro_derive` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:7:3
|
LL | #[unsafe(proc_macro_derive(Foo))]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: expected identifier, found keyword `unsafe`
--> $DIR/proc-unsafe-attributes.rs:12:21
|
@ -132,6 +108,30 @@ LL - #[proc_macro_derive(unsafe(Foo))]
LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|
error: `proc_macro_attribute` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:18:3
|
LL | #[unsafe(proc_macro_attribute)]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:23:3
|
LL | #[unsafe(allow(dead_code))]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
--> $DIR/proc-unsafe-attributes.rs:27:3
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error[E0452]: malformed lint attribute input
--> $DIR/proc-unsafe-attributes.rs:27:16
|

View file

@ -0,0 +1,10 @@
// This is a regression test for https://github.com/rust-lang/rust/issues/148453
// We want the `cannot find attribute` error to appear before `is not an unsafe attribute`
//@ edition: 2024
#[unsafe(does_not_exist)]
//~^ ERROR cannot find attribute
//~| ERROR is not an unsafe attribute
fn aa() {}
fn main() {}

View file

@ -0,0 +1,16 @@
error: cannot find attribute `does_not_exist` in this scope
--> $DIR/unsafe-nonexistent-attribute.rs:5:10
|
LL | #[unsafe(does_not_exist)]
| ^^^^^^^^^^^^^^
error: `does_not_exist` is not an unsafe attribute
--> $DIR/unsafe-nonexistent-attribute.rs:5:3
|
LL | #[unsafe(does_not_exist)]
| ^^^^^^ this is not an unsafe attribute
|
= note: extraneous unsafe is not allowed in attributes
error: aborting due to 2 previous errors

View file

@ -3,6 +3,9 @@ error: `#[diagnostic::on_const]` can only be applied to trait impls
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | pub struct Foo;
| -------------- not a trait impl
|
note: the lint level is defined here
--> $DIR/misplaced_attr.rs:2:9
@ -15,18 +18,27 @@ error: `#[diagnostic::on_const]` can only be applied to trait impls
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | impl const PartialEq for Foo {
| ---------------------------- not a trait impl
error: `#[diagnostic::on_const]` can only be applied to trait impls
--> $DIR/misplaced_attr.rs:16:1
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | impl Foo {
| -------- not a trait impl
error: `#[diagnostic::on_const]` can only be applied to trait impls
--> $DIR/misplaced_attr.rs:25:5
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | fn partial_cmp(&self, other: &Foo) -> Option<std::cmp::Ordering> {
| ---------------------------------------------------------------- not a trait impl
error: aborting due to 4 previous errors

View file

@ -1,4 +1,4 @@
//@ compile-flags: --check-cfg=cfg(emscripten_wasm_eh)
#[cfg(not(emscripten_wasm_eh))]
#[cfg(emscripten_wasm_eh)]
//~^ ERROR `cfg(emscripten_wasm_eh)` is experimental
fn main() {}

View file

@ -1,8 +1,8 @@
error[E0658]: `cfg(emscripten_wasm_eh)` is experimental and subject to change
--> $DIR/feature-gate-cfg-emscripten-wasm-eh.rs:2:11
--> $DIR/feature-gate-cfg-emscripten-wasm-eh.rs:2:7
|
LL | #[cfg(not(emscripten_wasm_eh))]
| ^^^^^^^^^^^^^^^^^^
LL | #[cfg(emscripten_wasm_eh)]
| ^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(cfg_emscripten_wasm_eh)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

View file

@ -1,14 +1,3 @@
error: unsafe attribute used without unsafe
--> $DIR/ffi_const.rs:16:7
|
LL | #[ffi_const]
| ^^^^^^^^^ usage of unsafe attribute
|
help: wrap the attribute in `unsafe(...)`
|
LL | #[unsafe(ffi_const)]
| +++++++ +
error: `#[ffi_const]` attribute cannot be used on functions
--> $DIR/ffi_const.rs:4:1
|
@ -33,5 +22,16 @@ LL | #[unsafe(ffi_const)]
|
= help: `#[ffi_const]` can only be applied to foreign functions
error: unsafe attribute used without unsafe
--> $DIR/ffi_const.rs:16:7
|
LL | #[ffi_const]
| ^^^^^^^^^ usage of unsafe attribute
|
help: wrap the attribute in `unsafe(...)`
|
LL | #[unsafe(ffi_const)]
| +++++++ +
error: aborting due to 4 previous errors

View file

@ -1,14 +1,3 @@
error: unsafe attribute used without unsafe
--> $DIR/ffi_pure.rs:16:7
|
LL | #[ffi_pure]
| ^^^^^^^^ usage of unsafe attribute
|
help: wrap the attribute in `unsafe(...)`
|
LL | #[unsafe(ffi_pure)]
| +++++++ +
error: `#[ffi_pure]` attribute cannot be used on functions
--> $DIR/ffi_pure.rs:4:1
|
@ -33,5 +22,16 @@ LL | #[unsafe(ffi_pure)]
|
= help: `#[ffi_pure]` can only be applied to foreign functions
error: unsafe attribute used without unsafe
--> $DIR/ffi_pure.rs:16:7
|
LL | #[ffi_pure]
| ^^^^^^^^ usage of unsafe attribute
|
help: wrap the attribute in `unsafe(...)`
|
LL | #[unsafe(ffi_pure)]
| +++++++ +
error: aborting due to 4 previous errors

View file

@ -1,4 +1,5 @@
// E0277 should point exclusively at line 6, not the entire for loop span
//! Tests that the E0277 error span, generated by the `for` loop desugaring,
//! points exclusively to the loop header expression and not the full loop block.
fn main() {
for c in "asdf" {

View file

@ -1,5 +1,5 @@
error[E0277]: `&str` is not an iterator
--> $DIR/for-c-in-str.rs:4:14
--> $DIR/for-c-in-str.rs:5:14
|
LL | for c in "asdf" {
| ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`

View file

@ -0,0 +1,21 @@
//! Tests that a struct with a `next` method but without the `Iterator` trait
//! implementation yields an error in a `for` loop.
struct MyStruct {
x: isize,
y: isize,
}
impl MyStruct {
fn next(&mut self) -> Option<isize> {
Some(self.x)
}
}
pub fn main() {
let mut bogus = MyStruct { x: 1, y: 2 };
for x in bogus {
//~^ ERROR `MyStruct` is not an iterator
drop(x);
}
}

View file

@ -5,7 +5,7 @@ LL | for x in bogus {
| ^^^^^ `MyStruct` is not an iterator
|
help: the trait `Iterator` is not implemented for `MyStruct`
--> $DIR/for-loop-bogosity.rs:1:1
--> $DIR/for-loop-bogosity.rs:4:1
|
LL | struct MyStruct {
| ^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error[E0425]: cannot find value `foo` in this scope
--> $DIR/for-expn.rs:6:7
--> $DIR/for-loop-diagnostic-span.rs:6:7
|
LL | foo
| ^^^ not found in this scope

View file

@ -1,3 +1,5 @@
//! regression test for issue <https://github.com/rust-lang/rust/issues/16042>
pub fn main() {
let x = () + (); //~ ERROR cannot add `()` to `()`

View file

@ -1,5 +1,5 @@
error[E0369]: cannot add `()` to `()`
--> $DIR/for-loop-type-error.rs:2:16
--> $DIR/for-loop-type-error.rs:4:16
|
LL | let x = () + ();
| -- ^ -- ()

View file

@ -3,7 +3,8 @@
// Subtle changes in the desugaring can cause the
// type of elements in the vector to (incorrectly)
// fallback to `!` or `()`.
// regression test for issue <https://github.com/rust-lang/rust/issues/42618>
fn main() {
for i in Vec::new() { } //~ ERROR type annotations needed
for i in Vec::new() {} //~ ERROR type annotations needed
}

View file

@ -1,12 +1,12 @@
error[E0282]: type annotations needed
--> $DIR/for-loop-unconstrained-element-type.rs:8:14
--> $DIR/for-loop-unconstrained-element-type.rs:9:14
|
LL | for i in Vec::new() { }
LL | for i in Vec::new() {}
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
|
help: consider specifying the generic argument
|
LL | for i in Vec::<T>::new() { }
LL | for i in Vec::<T>::new() {}
| +++++
error: aborting due to 1 previous error

View file

@ -0,0 +1,29 @@
//! Tests for trait/type errors when dereferencing via macro in a for loop.
macro_rules! deref {
($e:expr) => {
*$e
};
}
fn f1(x: &mut i32) {
for _item in deref!(x) {}
//~^ ERROR `i32` is not an iterator
}
struct Wrapped(i32);
macro_rules! borrow_deref {
($e:expr) => {
&mut *$e
};
}
fn f2<'a>(mut iter: Box<dyn Iterator<Item = &'a mut i32>>) {
for Wrapped(item) in borrow_deref!(iter) {
//~^ ERROR mismatched types
*item = 0
}
}
fn main() {}

View file

@ -0,0 +1,22 @@
error[E0277]: `i32` is not an iterator
--> $DIR/iter-from-mac-call.rs:10:18
|
LL | for _item in deref!(x) {}
| ^^^^^^^^^ `i32` is not an iterator
|
= help: the trait `Iterator` is not implemented for `i32`
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
= note: required for `i32` to implement `IntoIterator`
error[E0308]: mismatched types
--> $DIR/iter-from-mac-call.rs:23:9
|
LL | for Wrapped(item) in borrow_deref!(iter) {
| ^^^^^^^^^^^^^ ------------------- this is an iterator with items of type `&mut i32`
| |
| expected `i32`, found `Wrapped`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.

View file

@ -1,21 +0,0 @@
struct MyStruct {
x: isize,
y: isize,
}
impl MyStruct {
fn next(&mut self) -> Option<isize> {
Some(self.x)
}
}
pub fn main() {
let mut bogus = MyStruct {
x: 1,
y: 2,
};
for x in bogus {
//~^ ERROR `MyStruct` is not an iterator
drop(x);
}
}

View file

@ -1,10 +0,0 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) {
for item in *things { *item = 0 }
//~^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
}
fn main() {}

View file

@ -1,26 +0,0 @@
macro_rules! deref {
($e:expr) => { *$e };
}
fn f1<'a>(mut iter: Box<dyn Iterator<Item=&'a mut u8>>) {
for item in deref!(iter) { *item = 0 }
//~^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
}
fn f2(x: &mut i32) {
for _item in deref!(x) {}
//~^ ERROR `i32` is not an iterator
}
struct Wrapped(i32);
macro_rules! borrow_deref {
($e:expr) => { &mut *$e };
}
fn f3<'a>(mut iter: Box<dyn Iterator<Item=&'a mut i32>>) {
for Wrapped(item) in borrow_deref!(iter) { *item = 0 }
//~^ ERROR mismatched types
}
fn main() {}

View file

@ -1,35 +0,0 @@
error[E0277]: `dyn Iterator<Item = &'a mut u8>` is not an iterator
--> $DIR/iter_from_mac_call.rs:6:17
|
LL | for item in deref!(iter) { *item = 0 }
| ^^^^^^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
|
= note: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
= note: required for `dyn Iterator<Item = &'a mut u8>` to implement `IntoIterator`
help: consider mutably borrowing here
|
LL | for item in &mut deref!(iter) { *item = 0 }
| ++++
error[E0277]: `i32` is not an iterator
--> $DIR/iter_from_mac_call.rs:11:18
|
LL | for _item in deref!(x) {}
| ^^^^^^^^^ `i32` is not an iterator
|
= help: the trait `Iterator` is not implemented for `i32`
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
= note: required for `i32` to implement `IntoIterator`
error[E0308]: mismatched types
--> $DIR/iter_from_mac_call.rs:22:9
|
LL | for Wrapped(item) in borrow_deref!(iter) { *item = 0 }
| ^^^^^^^^^^^^^ ------------------- this is an iterator with items of type `&mut i32`
| |
| expected `i32`, found `Wrapped`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.

View file

@ -1,6 +1,8 @@
#![feature(associated_type_defaults)]
trait Animal {
Type Result = u8;
//~^ ERROR expected one of
//~^ ERROR keyword `type` is written in the wrong case
}
fn main() {}

View file

@ -1,15 +1,10 @@
error: expected one of `!` or `::`, found `Result`
--> $DIR/assoc-type.rs:2:10
error: keyword `type` is written in the wrong case
--> $DIR/assoc-type.rs:4:5
|
LL | trait Animal {
| - while parsing this item list starting here
LL | Type Result = u8;
| ^^^^^^ expected one of `!` or `::`
LL |
LL | }
| - the item list ends here
| ^^^^
|
help: write keyword `type` in lowercase
help: write it in lowercase
|
LL - Type Result = u8;
LL + type Result = u8;

View file

@ -0,0 +1,27 @@
// Shows that we perform recovery on misspelled item keyword.
#![feature(associated_type_defaults)]
trait Animal {
Type Result = u8;
//~^ ERROR keyword `type` is written in the wrong case
}
Struct Foor {
//~^ ERROR keyword `struct` is written in the wrong case
hello: String,
}
Const A: u8 = 10;
//~^ ERROR keyword `const` is written in the wrong case
Fn code() {}
//~^ ERROR keyword `fn` is written in the wrong case
Static a: u8 = 0;
//~^ ERROR keyword `static` is written in the wrong case
usee a::b;
//~^ ERROR expected one of
fn main() {}

View file

@ -0,0 +1,74 @@
error: keyword `type` is written in the wrong case
--> $DIR/recovery.rs:6:5
|
LL | Type Result = u8;
| ^^^^
|
help: write it in lowercase
|
LL - Type Result = u8;
LL + type Result = u8;
|
error: keyword `struct` is written in the wrong case
--> $DIR/recovery.rs:10:1
|
LL | Struct Foor {
| ^^^^^^
|
help: write it in lowercase (notice the capitalization)
|
LL - Struct Foor {
LL + struct Foor {
|
error: keyword `const` is written in the wrong case
--> $DIR/recovery.rs:15:1
|
LL | Const A: u8 = 10;
| ^^^^^
|
help: write it in lowercase (notice the capitalization)
|
LL - Const A: u8 = 10;
LL + const A: u8 = 10;
|
error: keyword `fn` is written in the wrong case
--> $DIR/recovery.rs:18:1
|
LL | Fn code() {}
| ^^
|
help: write it in lowercase (notice the capitalization)
|
LL - Fn code() {}
LL + fn code() {}
|
error: keyword `static` is written in the wrong case
--> $DIR/recovery.rs:21:1
|
LL | Static a: u8 = 0;
| ^^^^^^
|
help: write it in lowercase (notice the capitalization)
|
LL - Static a: u8 = 0;
LL + static a: u8 = 0;
|
error: expected one of `!` or `::`, found `a`
--> $DIR/recovery.rs:24:6
|
LL | usee a::b;
| ^ expected one of `!` or `::`
|
help: there is a keyword `use` with a similar name
|
LL - usee a::b;
LL + use a::b;
|
error: aborting due to 6 previous errors

View file

@ -1,4 +1,3 @@
Static a = 0;
//~^ ERROR expected one of
Static a: u32 = 0;
//~^ ERROR keyword `static` is written in the wrong case
fn main() {}

View file

@ -1,13 +1,13 @@
error: expected one of `!` or `::`, found `a`
--> $DIR/static.rs:1:8
error: keyword `static` is written in the wrong case
--> $DIR/static.rs:1:1
|
LL | Static a = 0;
| ^ expected one of `!` or `::`
LL | Static a: u32 = 0;
| ^^^^^^
|
help: write keyword `static` in lowercase (notice the capitalization)
help: write it in lowercase (notice the capitalization)
|
LL - Static a = 0;
LL + static a = 0;
LL - Static a: u32 = 0;
LL + static a: u32 = 0;
|
error: aborting due to 1 previous error

View file

@ -1,4 +1,6 @@
Struct Foor {
//~^ ERROR expected one of
//~^ ERROR keyword `struct` is written in the wrong case
hello: String,
}
fn main() {}

View file

@ -1,10 +1,10 @@
error: expected one of `!` or `::`, found `Foor`
--> $DIR/struct.rs:1:8
error: keyword `struct` is written in the wrong case
--> $DIR/struct.rs:1:1
|
LL | Struct Foor {
| ^^^^ expected one of `!` or `::`
| ^^^^^^
|
help: write keyword `struct` in lowercase (notice the capitalization)
help: write it in lowercase (notice the capitalization)
|
LL - Struct Foor {
LL + struct Foor {

View file

@ -1,3 +1,4 @@
//! regression test for issue <https://github.com/rust-lang/rust/issues/122509>
//@ build-pass
//@ compile-flags: -C codegen-units=2 --emit asm

View file

@ -1,14 +1,14 @@
error[E0277]: `dyn Iterator<Item = &'a mut u8>` is not an iterator
--> $DIR/issue-20605.rs:6:17
--> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17
|
LL | for item in *things { *item = 0 }
LL | for item in *things {
| ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
|
= note: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
= note: required for `dyn Iterator<Item = &'a mut u8>` to implement `IntoIterator`
help: consider mutably borrowing here
|
LL | for item in &mut *things { *item = 0 }
LL | for item in &mut *things {
| ++++
error: aborting due to 1 previous error

View file

@ -1,14 +1,14 @@
error[E0277]: `dyn Iterator<Item = &'a mut u8>` is not an iterator
--> $DIR/issue-20605.rs:6:17
--> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17
|
LL | for item in *things { *item = 0 }
LL | for item in *things {
| ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
|
= note: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
= note: required for `dyn Iterator<Item = &'a mut u8>` to implement `IntoIterator`
help: consider mutably borrowing here
|
LL | for item in &mut *things { *item = 0 }
LL | for item in &mut *things {
| ++++
error: aborting due to 1 previous error

View file

@ -0,0 +1,15 @@
//! Tests that dereferencing a Box<dyn Iterator> in a for loop correctly yields an error,
//! as the unsized trait object does not implement IntoIterator.
//! regression test for <https://github.com/rust-lang/rust/issues/20605>
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
fn changer<'a>(mut things: Box<dyn Iterator<Item = &'a mut u8>>) {
for item in *things {
//~^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
*item = 0
}
}
fn main() {}