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:
commit
3e2dbcdd3a
86 changed files with 645 additions and 447 deletions
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ mod interface;
|
|||
pub mod parser;
|
||||
|
||||
mod lints;
|
||||
mod safety;
|
||||
mod session_diagnostics;
|
||||
mod target_checking;
|
||||
pub mod validate_attr;
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
116
compiler/rustc_attr_parsing/src/safety.rs
Normal file
116
compiler/rustc_attr_parsing/src/safety.rs
Normal 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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,4 +62,8 @@ pub enum AttributeLintKind {
|
|||
target: Target,
|
||||
target_span: Span,
|
||||
},
|
||||
UnsafeAttrOutsideUnsafe {
|
||||
attribute_name_span: Span,
|
||||
sugg_spans: (Span, Span),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`),
|
||||
|
|
|
|||
|
|
@ -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 ---------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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) { }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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) { }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
||||
|
|
|
|||
10
tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs
Normal file
10
tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs
Normal 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() {}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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" {
|
||||
|
|
@ -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()`
|
||||
21
tests/ui/for-loop-while/for-loop-bogosity.rs
Normal file
21
tests/ui/for-loop-while/for-loop-bogosity.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
@ -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
|
||||
|
|
@ -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 `()`
|
||||
|
||||
|
|
@ -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 = () + ();
|
||||
| -- ^ -- ()
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
29
tests/ui/for-loop-while/iter-from-mac-call.rs
Normal file
29
tests/ui/for-loop-while/iter-from-mac-call.rs
Normal 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() {}
|
||||
22
tests/ui/for-loop-while/iter-from-mac-call.stderr
Normal file
22
tests/ui/for-loop-while/iter-from-mac-call.stderr
Normal 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`.
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
27
tests/ui/parser/misspelled-keywords/recovery.rs
Normal file
27
tests/ui/parser/misspelled-keywords/recovery.rs
Normal 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() {}
|
||||
74
tests/ui/parser/misspelled-keywords/recovery.stderr
Normal file
74
tests/ui/parser/misspelled-keywords/recovery.stderr
Normal 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
|
||||
|
||||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
Struct Foor {
|
||||
//~^ ERROR expected one of
|
||||
//~^ ERROR keyword `struct` is written in the wrong case
|
||||
hello: String,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
15
tests/ui/traits/dyn-iterator-deref-in-for-loop.rs
Normal file
15
tests/ui/traits/dyn-iterator-deref-in-for-loop.rs
Normal 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() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue