diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e683758d6df2..05aa600e649eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 42461bd5eb106..2790916891a15 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -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) { diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index a8aa63bd05ee6..bd228315b2c95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -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, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 8006fb963b198..0c0915558089e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -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, diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b7a6a1ef6d667..87e29b7b0de6e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -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, 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::>(); @@ -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, diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 046cca4c742b0..7a7f2555287a2 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -98,6 +98,7 @@ mod interface; pub mod parser; mod lints; +mod safety; mod session_diagnostics; mod target_checking; pub mod validate_attr; diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 3a2a370466961..a23884d7f71eb 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -98,5 +98,17 @@ pub fn emit_attribute_lint(lint: &AttributeLint, 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 }, + }, + ), } } diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs new file mode 100644 index 0000000000000..ff385bf13aaa9 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -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), + 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", + ); + } + } + } +} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 8d783503f7be0..f94f0867451f0 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -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, diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 4065fe7ce1735..c57e0baea05f6 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -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, - 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), + }); } } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 5ca4fff948788..b24e3065622d2 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -54,6 +54,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result 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 { - 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, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6d048c120a211..20fb321307ac5 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2158,11 +2158,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut span: Option = 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), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8f297677ff852..94c47b06e6353 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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::>().into_boxed_slice(), - span: path.span, + segments: path + .segments + .iter() + .map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) }) + .collect::>() + .into_boxed_slice(), + span: lower_span(path.span), } } } diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 8563937f70d3c..a4c60fd2cc1ad 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -62,4 +62,8 @@ pub enum AttributeLintKind { target: Target, target_span: Span, }, + UnsafeAttrOutsideUnsafe { + attribute_name_span: Span, + sugg_spans: (Span, Span), + }, } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8bf9f8420c05e..6752ddbc5706e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -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); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bf721154d73be..75e7af4c11733 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -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 diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index e376d7d2ab883..87ccd114ee97e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -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, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0687490645d3f..6568aa6fd5aa4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -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> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 326fdaf9cec92..abdc41eb57c21 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -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, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 86991f047e46d..abc0ffa87d3d0 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -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 { + 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 } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 91a20a12b6334..09ac3ae1c3a92 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -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 diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e3b2a922c9afd..1289867987158 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -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 }, ); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7c7e9118d590f..872a48efa3661 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -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"), diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 9b9cc80a606c6..20353c65d491e 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -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, diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index ab765ebcb7fa7..823bd4917b3d5 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -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, diff --git a/library/std/src/num/f128.rs b/library/std/src/num/f128.rs index 3b787713afa24..6f1fd2975b714 100644 --- a/library/std/src/num/f128.rs +++ b/library/std/src/num/f128.rs @@ -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, diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs index 4af21c95c9baf..20d0b4e1e552b 100644 --- a/library/std/src/num/f16.rs +++ b/library/std/src/num/f16.rs @@ -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, diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index 09ced388a3399..97ae334e19946 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -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 diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 79adf076e4b1a..aaeaa86ca77e1 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -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 diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index d888e63275cda..7e46b85ff9af3 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -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, diff --git a/src/ci/scripts/checkout-submodules.sh b/src/ci/scripts/checkout-submodules.sh index 5a422afc42b46..e38e20d47c3db 100755 --- a/src/ci/scripts/checkout-submodules.sh +++ b/src/ci/scripts/checkout-submodules.sh @@ -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 { diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md index a9ff1ebd10488..d5e3125fd3c79 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md @@ -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 . +`-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 diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index 50472ed3638e9..f9ff4c84c129d 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -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::::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 }) } diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index a37700f2e8538..0f3f2f37ebf26 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -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 diff --git a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs index dfe154c1c8314..c641c0a63d541 100644 --- a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs +++ b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.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`), diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index e58ee1a6d4e4b..5b03f9ed6c679 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -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 --------------------------------------------------------------------- diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs index ebcab178f209b..75c0939fbfcde 100644 --- a/tests/incremental/hashes/inherent_impls.rs +++ b/tests/incremental/hashes/inherent_impls.rs @@ -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) { } } diff --git a/tests/incremental/hashes/statics.rs b/tests/incremental/hashes/statics.rs index cd394ed866e9f..94548eeef7fd1 100644 --- a/tests/incremental/hashes/statics.rs +++ b/tests/incremental/hashes/statics.rs @@ -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; diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs index 03ca672af1316..d4ac69a8b55de 100644 --- a/tests/incremental/hashes/trait_impls.rs +++ b/tests/incremental/hashes/trait_impls.rs @@ -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) { } } diff --git a/tests/ui/README.md b/tests/ui/README.md index 9864d88ceb079..25e870fd8f188 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -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 . @@ -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. diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr index 0825cf794083d..8ab945e0f182e 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -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 diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 94edb263a6afe..4527cf676f78a 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -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 | diff --git a/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs new file mode 100644 index 0000000000000..c7d7b712925dc --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs @@ -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() {} diff --git a/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr new file mode 100644 index 0000000000000..42d9425ed31fa --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr @@ -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 + diff --git a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr index a12c00c74d055..baa0b11f798b9 100644 --- a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr +++ b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr @@ -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 { + | ---------------------------------------------------------------- not a trait impl error: aborting due to 4 previous errors diff --git a/tests/ui/warnings/hello-world.rs b/tests/ui/entry-point/hello-world.rs similarity index 100% rename from tests/ui/warnings/hello-world.rs rename to tests/ui/entry-point/hello-world.rs diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs index 232061e239c93..a13e7fa317f5b 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs +++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs @@ -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() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr index 67769e3c7586b..a829c9b93a566 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr +++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr @@ -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 diff --git a/tests/ui/ffi-attrs/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr index f3be925431836..af54486e433ca 100644 --- a/tests/ui/ffi-attrs/ffi_const.stderr +++ b/tests/ui/ffi-attrs/ffi_const.stderr @@ -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 diff --git a/tests/ui/ffi-attrs/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr index da1eae975ac2d..11e9199b40f4b 100644 --- a/tests/ui/ffi-attrs/ffi_pure.stderr +++ b/tests/ui/ffi-attrs/ffi_pure.stderr @@ -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 diff --git a/tests/ui/for/for-c-in-str.rs b/tests/ui/for-loop-while/for-c-in-str.rs similarity index 75% rename from tests/ui/for/for-c-in-str.rs rename to tests/ui/for-loop-while/for-c-in-str.rs index b086128d28cbc..b3190101da09d 100644 --- a/tests/ui/for/for-c-in-str.rs +++ b/tests/ui/for-loop-while/for-c-in-str.rs @@ -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" { diff --git a/tests/ui/for/for-c-in-str.stderr b/tests/ui/for-loop-while/for-c-in-str.stderr similarity index 92% rename from tests/ui/for/for-c-in-str.stderr rename to tests/ui/for-loop-while/for-c-in-str.stderr index 475cf8c887491..30749274f919c 100644 --- a/tests/ui/for/for-c-in-str.stderr +++ b/tests/ui/for-loop-while/for-c-in-str.stderr @@ -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()` diff --git a/tests/ui/for/for-else-err.rs b/tests/ui/for-loop-while/for-else-err.rs similarity index 100% rename from tests/ui/for/for-else-err.rs rename to tests/ui/for-loop-while/for-else-err.rs diff --git a/tests/ui/for/for-else-err.stderr b/tests/ui/for-loop-while/for-else-err.stderr similarity index 100% rename from tests/ui/for/for-else-err.stderr rename to tests/ui/for-loop-while/for-else-err.stderr diff --git a/tests/ui/for/for-else-let-else-err.rs b/tests/ui/for-loop-while/for-else-let-else-err.rs similarity index 100% rename from tests/ui/for/for-else-let-else-err.rs rename to tests/ui/for-loop-while/for-else-let-else-err.rs diff --git a/tests/ui/for/for-else-let-else-err.stderr b/tests/ui/for-loop-while/for-else-let-else-err.stderr similarity index 100% rename from tests/ui/for/for-else-let-else-err.stderr rename to tests/ui/for-loop-while/for-else-let-else-err.stderr diff --git a/tests/ui/for-loop-while/for-loop-bogosity.rs b/tests/ui/for-loop-while/for-loop-bogosity.rs new file mode 100644 index 0000000000000..19117620c5e67 --- /dev/null +++ b/tests/ui/for-loop-while/for-loop-bogosity.rs @@ -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 { + 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); + } +} diff --git a/tests/ui/for/for-loop-bogosity.stderr b/tests/ui/for-loop-while/for-loop-bogosity.stderr similarity index 92% rename from tests/ui/for/for-loop-bogosity.stderr rename to tests/ui/for-loop-while/for-loop-bogosity.stderr index f4d99671f8e0c..53bd32e337fd8 100644 --- a/tests/ui/for/for-loop-bogosity.stderr +++ b/tests/ui/for-loop-while/for-loop-bogosity.stderr @@ -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 { | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/for/for-expn.rs b/tests/ui/for-loop-while/for-loop-diagnostic-span.rs similarity index 100% rename from tests/ui/for/for-expn.rs rename to tests/ui/for-loop-while/for-loop-diagnostic-span.rs diff --git a/tests/ui/for/for-expn.stderr b/tests/ui/for-loop-while/for-loop-diagnostic-span.stderr similarity index 83% rename from tests/ui/for/for-expn.stderr rename to tests/ui/for-loop-while/for-loop-diagnostic-span.stderr index 00822324039f0..d2fc05f054a00 100644 --- a/tests/ui/for/for-expn.stderr +++ b/tests/ui/for-loop-while/for-loop-diagnostic-span.stderr @@ -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 diff --git a/tests/ui/for/for-loop-refutable-pattern-error-message.rs b/tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.rs similarity index 100% rename from tests/ui/for/for-loop-refutable-pattern-error-message.rs rename to tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.rs diff --git a/tests/ui/for/for-loop-refutable-pattern-error-message.stderr b/tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.stderr similarity index 100% rename from tests/ui/for/for-loop-refutable-pattern-error-message.stderr rename to tests/ui/for-loop-while/for-loop-refutable-pattern-error-message.stderr diff --git a/tests/ui/for/for-loop-type-error.rs b/tests/ui/for-loop-while/for-loop-type-error.rs similarity index 62% rename from tests/ui/for/for-loop-type-error.rs rename to tests/ui/for-loop-while/for-loop-type-error.rs index 8d9fc20f0d0d6..895f1985a6199 100644 --- a/tests/ui/for/for-loop-type-error.rs +++ b/tests/ui/for-loop-while/for-loop-type-error.rs @@ -1,3 +1,5 @@ +//! regression test for issue + pub fn main() { let x = () + (); //~ ERROR cannot add `()` to `()` diff --git a/tests/ui/for/for-loop-type-error.stderr b/tests/ui/for-loop-while/for-loop-type-error.stderr similarity index 86% rename from tests/ui/for/for-loop-type-error.stderr rename to tests/ui/for-loop-while/for-loop-type-error.stderr index 393becd1b3452..88f383444cb3f 100644 --- a/tests/ui/for/for-loop-type-error.stderr +++ b/tests/ui/for-loop-while/for-loop-type-error.stderr @@ -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 = () + (); | -- ^ -- () diff --git a/tests/ui/for/for-loop-unconstrained-element-type.rs b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs similarity index 63% rename from tests/ui/for/for-loop-unconstrained-element-type.rs rename to tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs index 0c7a3516a14ca..4fff6df5f4d39 100644 --- a/tests/ui/for/for-loop-unconstrained-element-type.rs +++ b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.rs @@ -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 fn main() { - for i in Vec::new() { } //~ ERROR type annotations needed + for i in Vec::new() {} //~ ERROR type annotations needed } diff --git a/tests/ui/for/for-loop-unconstrained-element-type.stderr b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr similarity index 72% rename from tests/ui/for/for-loop-unconstrained-element-type.stderr rename to tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr index 3add3ae2eeb21..3b3fa6e7b5c66 100644 --- a/tests/ui/for/for-loop-unconstrained-element-type.stderr +++ b/tests/ui/for-loop-while/for-loop-unconstrained-element-type.stderr @@ -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::::new() { } +LL | for i in Vec::::new() {} | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/for-loop-while/iter-from-mac-call.rs b/tests/ui/for-loop-while/iter-from-mac-call.rs new file mode 100644 index 0000000000000..58177444c3f98 --- /dev/null +++ b/tests/ui/for-loop-while/iter-from-mac-call.rs @@ -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>) { + for Wrapped(item) in borrow_deref!(iter) { + //~^ ERROR mismatched types + *item = 0 + } +} + +fn main() {} diff --git a/tests/ui/for-loop-while/iter-from-mac-call.stderr b/tests/ui/for-loop-while/iter-from-mac-call.stderr new file mode 100644 index 0000000000000..4cde6a8a86d38 --- /dev/null +++ b/tests/ui/for-loop-while/iter-from-mac-call.stderr @@ -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`. diff --git a/tests/ui/for/for-loop-bogosity.rs b/tests/ui/for/for-loop-bogosity.rs deleted file mode 100644 index 9341dea0974b4..0000000000000 --- a/tests/ui/for/for-loop-bogosity.rs +++ /dev/null @@ -1,21 +0,0 @@ -struct MyStruct { - x: isize, - y: isize, -} - -impl MyStruct { - fn next(&mut self) -> Option { - 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); - } -} diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs deleted file mode 100644 index 5c56e64a01727..0000000000000 --- a/tests/ui/for/issue-20605.rs +++ /dev/null @@ -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>) { - for item in *things { *item = 0 } - //~^ ERROR `dyn Iterator` is not an iterator -} - -fn main() {} diff --git a/tests/ui/for/iter_from_mac_call.rs b/tests/ui/for/iter_from_mac_call.rs deleted file mode 100644 index 8df21456222c4..0000000000000 --- a/tests/ui/for/iter_from_mac_call.rs +++ /dev/null @@ -1,26 +0,0 @@ -macro_rules! deref { - ($e:expr) => { *$e }; -} - -fn f1<'a>(mut iter: Box>) { - for item in deref!(iter) { *item = 0 } - //~^ ERROR `dyn Iterator` 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>) { - for Wrapped(item) in borrow_deref!(iter) { *item = 0 } - //~^ ERROR mismatched types -} - -fn main() {} diff --git a/tests/ui/for/iter_from_mac_call.stderr b/tests/ui/for/iter_from_mac_call.stderr deleted file mode 100644 index e62efb250e299..0000000000000 --- a/tests/ui/for/iter_from_mac_call.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0277]: `dyn Iterator` 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` - | - = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied - = note: required for `dyn Iterator` 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`. diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.rs b/tests/ui/parser/misspelled-keywords/assoc-type.rs index a6b694a2abe6b..31328d010ae91 100644 --- a/tests/ui/parser/misspelled-keywords/assoc-type.rs +++ b/tests/ui/parser/misspelled-keywords/assoc-type.rs @@ -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() {} diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.stderr b/tests/ui/parser/misspelled-keywords/assoc-type.stderr index e529b477c05bc..4a777a558c727 100644 --- a/tests/ui/parser/misspelled-keywords/assoc-type.stderr +++ b/tests/ui/parser/misspelled-keywords/assoc-type.stderr @@ -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; diff --git a/tests/ui/parser/misspelled-keywords/recovery.rs b/tests/ui/parser/misspelled-keywords/recovery.rs new file mode 100644 index 0000000000000..f56709c0ce97f --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/recovery.rs @@ -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() {} diff --git a/tests/ui/parser/misspelled-keywords/recovery.stderr b/tests/ui/parser/misspelled-keywords/recovery.stderr new file mode 100644 index 0000000000000..6c2e8261e9719 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/recovery.stderr @@ -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 + diff --git a/tests/ui/parser/misspelled-keywords/static.rs b/tests/ui/parser/misspelled-keywords/static.rs index 240f4f52c8dc8..29dd21b6b56c7 100644 --- a/tests/ui/parser/misspelled-keywords/static.rs +++ b/tests/ui/parser/misspelled-keywords/static.rs @@ -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() {} diff --git a/tests/ui/parser/misspelled-keywords/static.stderr b/tests/ui/parser/misspelled-keywords/static.stderr index 0df40bcdc33b5..75c34f4839505 100644 --- a/tests/ui/parser/misspelled-keywords/static.stderr +++ b/tests/ui/parser/misspelled-keywords/static.stderr @@ -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 diff --git a/tests/ui/parser/misspelled-keywords/struct.rs b/tests/ui/parser/misspelled-keywords/struct.rs index 0f64dec6f56b3..5c76ce7622f95 100644 --- a/tests/ui/parser/misspelled-keywords/struct.rs +++ b/tests/ui/parser/misspelled-keywords/struct.rs @@ -1,4 +1,6 @@ Struct Foor { -//~^ ERROR expected one of + //~^ ERROR keyword `struct` is written in the wrong case hello: String, } + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/struct.stderr b/tests/ui/parser/misspelled-keywords/struct.stderr index af8614ef14b71..a6709111d4ae7 100644 --- a/tests/ui/parser/misspelled-keywords/struct.stderr +++ b/tests/ui/parser/misspelled-keywords/struct.stderr @@ -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 { diff --git a/tests/ui/warnings/no-explicit-path-issue-122509.rs b/tests/ui/resolve/no-explicit-path.rs similarity index 79% rename from tests/ui/warnings/no-explicit-path-issue-122509.rs rename to tests/ui/resolve/no-explicit-path.rs index 5be4b174076db..11a5b78ab910e 100644 --- a/tests/ui/warnings/no-explicit-path-issue-122509.rs +++ b/tests/ui/resolve/no-explicit-path.rs @@ -1,3 +1,4 @@ +//! regression test for issue //@ build-pass //@ compile-flags: -C codegen-units=2 --emit asm diff --git a/tests/ui/for/issue-20605.current.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr similarity index 81% rename from tests/ui/for/issue-20605.current.stderr rename to tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr index 1a66cb4146495..b5a9b82a93a3e 100644 --- a/tests/ui/for/issue-20605.current.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr @@ -1,14 +1,14 @@ error[E0277]: `dyn Iterator` 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` | = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required for `dyn Iterator` 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 diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr similarity index 81% rename from tests/ui/for/issue-20605.next.stderr rename to tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr index 1a66cb4146495..b5a9b82a93a3e 100644 --- a/tests/ui/for/issue-20605.next.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr @@ -1,14 +1,14 @@ error[E0277]: `dyn Iterator` 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` | = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required for `dyn Iterator` 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 diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs b/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs new file mode 100644 index 0000000000000..04587df1555d7 --- /dev/null +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.rs @@ -0,0 +1,15 @@ +//! Tests that dereferencing a Box in a for loop correctly yields an error, +//! as the unsized trait object does not implement IntoIterator. +//! regression test for +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +fn changer<'a>(mut things: Box>) { + for item in *things { + //~^ ERROR `dyn Iterator` is not an iterator + *item = 0 + } +} + +fn main() {} diff --git a/tests/ui/trait-objects/trait-object-lifetime-conversion-47638.rs b/tests/ui/traits/object/trait-object-lifetime-conversion.rs similarity index 100% rename from tests/ui/trait-objects/trait-object-lifetime-conversion-47638.rs rename to tests/ui/traits/object/trait-object-lifetime-conversion.rs