diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 83cebed3a4594..139140af3e033 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; +use rustc_errors::StashKey; use rustc_hir::def::{DefKind, PartialRes, PerNS, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg}; @@ -298,7 +299,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { sym::return_type_notation, ); } - err.emit(); + err.stash(path_span, StashKey::ReturnTypeNotation); ( GenericArgsCtor { args: Default::default(), diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index d2f743f6c5d8f..badf696606e94 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -20,7 +20,9 @@ use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use thin_vec::ThinVec; use crate::context::{AcceptContext, ShouldEmit, Stage}; -use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; +use crate::parser::{ + AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser, +}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, @@ -363,6 +365,7 @@ fn parse_cfg_attr_internal<'a>( let meta = MetaItemOrLitParser::parse_single( parser, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, + AllowExprMetavar::Yes, )?; let pred_span = pred_start.with_hi(parser.token.span.hi()); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 7377159be370a..f3612afe69e5e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -12,7 +12,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; -use crate::parser::MetaItemOrLitParser; +use crate::parser::{AllowExprMetavar, MetaItemOrLitParser}; use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry}; #[derive(Clone)] @@ -94,6 +94,7 @@ pub fn parse_cfg_select( let meta = MetaItemOrLitParser::parse_single( p, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, + AllowExprMetavar::Yes, ) .map_err(|diag| diag.emit())?; let cfg_span = meta.span(); diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 63780676bead9..8abcaeb5fbf53 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -470,11 +470,12 @@ fn parse_filter(input: Symbol) -> FilterFormatString { // if the integer type has been resolved, to allow targeting all integers. // `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet, // from the `Display` impl of `InferTy` to be precise. + // `"{union|enum|struct}"` is used as a special selector for ADTs. // // Don't try to format these later! - Position::ArgumentNamed(arg @ ("integer" | "integral" | "float")) => { - LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))) - } + Position::ArgumentNamed( + arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"), + ) => LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))), Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)), Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces), diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index f75f63a0e811a..fa66dec6a1568 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -14,7 +14,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage}; use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState}; -use crate::parser::{ArgParser, PathParser, RefPathParser}; +use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -139,6 +139,7 @@ impl<'sess> AttributeParser<'sess, Early> { emit_errors: ShouldEmit, parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option, template: &AttributeTemplate, + allow_expr_metavar: AllowExprMetavar, ) -> Option { let ast::AttrKind::Normal(normal_attr) = &attr.kind else { panic!("parse_single called on a doc attr") @@ -152,6 +153,7 @@ impl<'sess> AttributeParser<'sess, Early> { &parts, &sess.psess, emit_errors, + allow_expr_metavar, )?; Self::parse_single_args( sess, @@ -333,6 +335,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { &parts, &self.sess.psess, self.stage.should_emit(), + AllowExprMetavar::No, ) else { continue; }; diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 07f246319dec8..6e8a500967363 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -109,6 +109,7 @@ impl ArgParser { parts: &[Symbol], psess: &'sess ParseSess, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> Option { Some(match value { AttrArgs::Empty => Self::NoArgs, @@ -122,6 +123,7 @@ impl ArgParser { args.dspan.entire(), psess, ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }, + allow_expr_metavar, ) { Ok(p) => return Some(ArgParser::List(p)), Err(e) => { @@ -147,9 +149,15 @@ impl ArgParser { } Self::List( - MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit) - .map_err(|e| should_emit.emit_err(e)) - .ok()?, + MetaItemListParser::new( + &args.tokens, + args.dspan.entire(), + psess, + should_emit, + allow_expr_metavar, + ) + .map_err(|e| should_emit.emit_err(e)) + .ok()?, ) } AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser { @@ -217,8 +225,9 @@ impl MetaItemOrLitParser { pub fn parse_single<'sess>( parser: &mut Parser<'sess>, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> PResult<'sess, MetaItemOrLitParser> { - let mut this = MetaItemListParserContext { parser, should_emit }; + let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar }; this.parse_meta_item_inner() } @@ -404,9 +413,19 @@ fn expr_to_lit<'sess>( } } +/// Whether expansions of `expr` metavariables from decrarative macros +/// are permitted. Used when parsing meta items; currently, only `cfg` predicates +/// enable this option +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AllowExprMetavar { + No, + Yes, +} + struct MetaItemListParserContext<'a, 'sess> { parser: &'a mut Parser<'sess>, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, } impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { @@ -447,20 +466,44 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { Ok(lit) } - fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> { - if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() { - return if has_meta_form { - let attr_item = self - .parser - .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { - MetaItemListParserContext { parser: this, should_emit: self.should_emit } - .parse_attr_item() - }) - .unwrap(); - Ok(attr_item) - } else { - self.parser.unexpected_any() - }; + fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> { + if let Some(metavar) = self.parser.token.is_metavar_seq() { + match (metavar, self.allow_expr_metavar) { + (kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => { + return self + .parser + .eat_metavar_seq(kind, |this| { + MetaItemListParserContext { + parser: this, + should_emit: self.should_emit, + allow_expr_metavar: AllowExprMetavar::Yes, + } + .parse_meta_item() + }) + .ok_or_else(|| { + self.parser.unexpected_any::().unwrap_err() + }); + } + (MetaVarKind::Meta { has_meta_form }, _) => { + return if has_meta_form { + let attr_item = self + .parser + .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { + MetaItemListParserContext { + parser: this, + should_emit: self.should_emit, + allow_expr_metavar: self.allow_expr_metavar, + } + .parse_meta_item() + }) + .unwrap(); + Ok(attr_item) + } else { + self.parser.unexpected_any() + }; + } + _ => {} + } } let path = self.parser.parse_path(PathStyle::Mod)?; @@ -469,8 +512,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { let args = if self.parser.check(exp!(OpenParen)) { let start = self.parser.token.span; let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| { - MetaItemListParserContext { parser, should_emit: self.should_emit } - .parse_meta_item_inner() + MetaItemListParserContext { + parser, + should_emit: self.should_emit, + allow_expr_metavar: self.allow_expr_metavar, + } + .parse_meta_item_inner() })?; let end = self.parser.prev_token.span; ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) }) @@ -492,7 +539,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) } else { let prev_pros = self.parser.approx_token_stream_pos(); - match self.parse_attr_item() { + match self.parse_meta_item() { Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)), Err(err) => { // If `parse_attr_item` made any progress, it likely has a more precise error we should prefer @@ -580,13 +627,15 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { psess: &'sess ParseSess, span: Span, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> PResult<'sess, MetaItemListParser> { let mut parser = Parser::new(psess, tokens, None); if let ShouldEmit::ErrorsAndLints { recovery } = should_emit { parser = parser.recovery(recovery); } - let mut this = MetaItemListParserContext { parser: &mut parser, should_emit }; + let mut this = + MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar }; // Presumably, the majority of the time there will only be one attr. let mut sub_parsers = ThinVec::with_capacity(1); @@ -618,8 +667,15 @@ impl MetaItemListParser { span: Span, psess: &'sess ParseSess, should_emit: ShouldEmit, + allow_expr_metavar: AllowExprMetavar, ) -> Result> { - MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit) + MetaItemListParserContext::parse( + tokens.clone(), + psess, + span, + should_emit, + allow_expr_metavar, + ) } /// Lets you pick and choose as what you want to parse each element in the list diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 3ebde949b99bc..c4a458089f2d2 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -4,10 +4,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrStyle, token}; -use rustc_attr_parsing as attr; -use rustc_attr_parsing::parser::MetaItemOrLitParser; +use rustc_attr_parsing::parser::{AllowExprMetavar, MetaItemOrLitParser}; use rustc_attr_parsing::{ - AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry, + self as attr, AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry, }; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_hir::attrs::CfgEntry; @@ -44,6 +43,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8e4039b32d942..ec5951e50e3a8 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -10,9 +10,10 @@ use rustc_ast::{ self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; -use rustc_attr_parsing as attr; +use rustc_attr_parsing::parser::AllowExprMetavar; use rustc_attr_parsing::{ - AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg, + self as attr, AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, + parse_cfg, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::msg; @@ -402,6 +403,7 @@ impl<'a> StripUnconfigured<'a> { emit_errors, parse_cfg, &CFG_TEMPLATE, + AllowExprMetavar::Yes, ) else { // Cfg attribute was not parsable, give up return EvalConfigResult::True; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 76a9a6f9d03d9..640d0746fe1a2 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,6 +13,7 @@ use rustc_ast::{ TyKind, token, }; use rustc_ast_pretty::pprust; +use rustc_attr_parsing::parser::AllowExprMetavar; use rustc_attr_parsing::{ AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg, validate_attr, @@ -2224,6 +2225,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, parse_cfg, &CFG_TEMPLATE, + AllowExprMetavar::Yes, ) else { // Cfg attribute was not parsable, give up return EvalConfigResult::True; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1c999f1ffc93a..fcd4cb938bf73 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1807,6 +1807,13 @@ pub(crate) struct CmseImplTrait { pub(crate) struct BadReturnTypeNotation { #[primary_span] pub span: Span, + #[suggestion( + "furthermore, argument types not allowed with return type notation", + applicability = "maybe-incorrect", + code = "(..)", + style = "verbose" + )] + pub suggestion: Option, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 9396bf6352c59..18c9baca051b3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -26,7 +26,7 @@ use rustc_ast::LitKind; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level, StashKey, struct_span_code_err, }; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -3015,7 +3015,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { - let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + let guar = self + .dcx() + .emit_err(BadReturnTypeNotation { span: hir_ty.span, suggestion: None }); Ty::new_error(tcx, guar) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { @@ -3077,12 +3079,95 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // If we encounter a type relative path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore // it's certainly in an illegal position. - hir::TyKind::Path(hir::QPath::TypeRelative(_, segment)) + hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) if segment.args.is_some_and(|args| { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { - let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + let guar = if let hir::Node::LetStmt(stmt) = tcx.parent_hir_node(hir_ty.hir_id) + && let None = stmt.init + && let hir::TyKind::Path(hir::QPath::Resolved(_, self_ty_path)) = + hir_self_ty.kind + && let Res::Def(DefKind::Enum | DefKind::Struct | DefKind::Union, def_id) = + self_ty_path.res + && let Some(_) = tcx + .inherent_impls(def_id) + .iter() + .flat_map(|imp| { + tcx.associated_items(*imp).filter_by_name_unhygienic(segment.ident.name) + }) + .filter(|assoc| { + matches!(assoc.kind, ty::AssocKind::Fn { has_self: false, .. }) + }) + .next() + { + // `let x: S::new(valid_in_ty_ctxt);` -> `let x = S::new(valid_in_ty_ctxt);` + let err = tcx + .dcx() + .struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ) + .with_span_suggestion_verbose( + stmt.pat.span.between(hir_ty.span), + "use `=` if you meant to assign", + " = ".to_string(), + Applicability::MaybeIncorrect, + ); + self.dcx().try_steal_replace_and_emit_err( + hir_ty.span, + StashKey::ReturnTypeNotation, + err, + ) + } else if let hir::Node::LetStmt(stmt) = tcx.parent_hir_node(hir_ty.hir_id) + && let None = stmt.init + && let hir::TyKind::Path(hir::QPath::Resolved(_, self_ty_path)) = + hir_self_ty.kind + && let Res::PrimTy(_) = self_ty_path.res + && self.dcx().has_stashed_diagnostic(hir_ty.span, StashKey::ReturnTypeNotation) + { + // `let x: i32::something(valid_in_ty_ctxt);` -> `let x = i32::something(valid_in_ty_ctxt);` + // FIXME: Check that `something` is a valid function in `i32`. + let err = tcx + .dcx() + .struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ) + .with_span_suggestion_verbose( + stmt.pat.span.between(hir_ty.span), + "use `=` if you meant to assign", + " = ".to_string(), + Applicability::MaybeIncorrect, + ); + self.dcx().try_steal_replace_and_emit_err( + hir_ty.span, + StashKey::ReturnTypeNotation, + err, + ) + } else { + let suggestion = if self + .dcx() + .has_stashed_diagnostic(hir_ty.span, StashKey::ReturnTypeNotation) + { + // We already created a diagnostic complaining that `foo(bar)` is wrong and + // should have been `foo(..)`. Instead, emit only the current error and + // include that prior suggestion. Changes are that the problems go further, + // but keep the suggestion just in case. Either way, we want a single error + // instead of two. + Some(segment.ident.span.shrink_to_hi().with_hi(hir_ty.span.hi())) + } else { + None + }; + let err = self + .dcx() + .create_err(BadReturnTypeNotation { span: hir_ty.span, suggestion }); + self.dcx().try_steal_replace_and_emit_err( + hir_ty.span, + StashKey::ReturnTypeNotation, + err, + ) + }; Ty::new_error(tcx, guar) } hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9d496c66f9686..893cd025a089d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3460,13 +3460,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?; let can_derive = match diagnostic_name { + sym::Copy | sym::Clone => true, + _ if adt.is_union() => false, sym::Default | sym::Eq | sym::PartialEq | sym::Ord | sym::PartialOrd - | sym::Clone - | sym::Copy | sym::Hash | sym::Debug => true, _ => false, diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 3b2102484bdf5..5bd2ca3139228 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -362,7 +362,7 @@ impl<'a> Parser<'a> { // init parsed, ty error // Could parse the type as if it were the initializer, it is likely there was a // typo in the code: `:` instead of `=`. Add suggestion and emit the error. - err.span_suggestion_short( + err.span_suggestion_verbose( colon_sp, "use `=` if you meant to assign", " =", @@ -1133,11 +1133,11 @@ impl<'a> Parser<'a> { } else { false }; - if suggest_eq { - e.span_suggestion_short( - colon_sp, + if suggest_eq && let Some(ty) = &local.ty { + e.span_suggestion_verbose( + local.pat.span.between(ty.span), "use `=` if you meant to assign", - "=", + " = ", Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e24389e0d74df..a8ca4faf5ab0d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1272,7 +1272,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_error.span) && base_error.could_be_expr => { - err.span_suggestion_short( + err.span_suggestion_verbose( pat_sp.between(ty_sp), "use `=` if you meant to assign", " = ", diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index d08e0fa3521bb..4ae6584fc2d1f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -124,8 +124,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) { - crate_local = true; + if let Some(adt) = self_ty.ty_adt_def() { + if adt.did().is_local() { + crate_local = true; + } + self_types.push(format!("{{{}}}", adt.descr())) } // Allow targeting all integers using `{integral}`, even if the exact type was resolved diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index ee2f8d9783cfe..4a6d5eb48f8f1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4037,12 +4037,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => return false, }; let is_derivable_trait = match diagnostic_name { - sym::Default => !adt.is_enum(), + sym::Copy | sym::Clone => true, + _ if adt.is_union() => false, sym::PartialEq | sym::PartialOrd => { let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); trait_pred.skip_binder().self_ty() == rhs_ty } - sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true, + sym::Eq | sym::Ord | sym::Hash | sym::Debug | sym::Default => true, _ => false, }; is_derivable_trait && diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 05d8e0d84f057..ecd1e34078e29 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1037,9 +1037,10 @@ impl Display for Arguments<'_> { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - crate_local, + all(crate_local, not(Self = "{union}")), note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`" ), + on(all(crate_local, Self = "{union}"), note = "manually `impl {This} for {Self}`"), on( from_desugaring = "FormatLiteral", label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`" diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index 3f06c9bd1d774..e1d9d80c97b62 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -62,25 +62,7 @@ pub macro thread_local_inner { // by translating it into a `cfg`ed block and recursing. // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate - (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { - #[cfg(true)] - { - $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, - - (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { - #[cfg(false)] - { - $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, - - (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + (@align $final_align:ident, cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { #[cfg($cfg_pred)] { $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1318d8dc27809..5de001838faff 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -198,41 +198,10 @@ pub macro thread_local_process_attrs { ); ), - // it's a nested `cfg_attr(true, ...)`; recurse into RHS - ( - [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; - @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; - $($rest:tt)* - ) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; - $($rest)* - ); - ), - - // it's a nested `cfg_attr(false, ...)`; recurse into RHS - ( - [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; - @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; - $($rest:tt)* - ) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; - $($rest)* - ); - ), - - // it's a nested `cfg_attr(..., ...)`; recurse into RHS ( [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; - @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:meta, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:expr, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; $($rest:tt)* ) => ( $crate::thread::local_impl::thread_local_process_attrs!( @@ -268,28 +237,8 @@ pub macro thread_local_process_attrs { ); ), - // `cfg_attr(true, ...)` attribute; parse it - ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(true, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - $($rest)* - ); - ), - - // `cfg_attr(false, ...)` attribute; parse it - ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(false, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_process_attrs!( - [] []; - @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; - [$($prev_align_attrs)*] [$($prev_other_attrs)*]; - $($rest)* - ); - ), - // `cfg_attr(..., ...)` attribute; parse it - ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( $crate::thread::local_impl::thread_local_process_attrs!( [] []; @processing_cfg_attr { pred: ($cfg_pred), rhs: [$($cfg_rhs)*] }; diff --git a/tests/ui/async-await/drop-option-future.rs b/tests/ui/async-await/drop-option-future.rs new file mode 100644 index 0000000000000..155b1d76e44ae --- /dev/null +++ b/tests/ui/async-await/drop-option-future.rs @@ -0,0 +1,16 @@ +//! Regression test for . + +//@ edition:2018 +//@ check-pass + +#![allow(dead_code)] +#![allow(unused_assignments)] + +async fn foo() { + let mut f = None; + let value = 0; + f = Some(async { value }); + core::mem::drop(f); +} + +fn main() { } diff --git a/tests/ui/issues/issue-52049.rs b/tests/ui/borrowck/non-promotable-static-ref.rs similarity index 53% rename from tests/ui/issues/issue-52049.rs rename to tests/ui/borrowck/non-promotable-static-ref.rs index efdcc44930567..44733493ec06f 100644 --- a/tests/ui/issues/issue-52049.rs +++ b/tests/ui/borrowck/non-promotable-static-ref.rs @@ -1,3 +1,5 @@ +//Test for https://github.com/rust-lang/rust/issues/52049 +//Tests that a non-promotable temp variable cannot be used as a static reference. fn foo(_: &'static u32) {} fn unpromotable(t: T) -> T { t } diff --git a/tests/ui/issues/issue-52049.stderr b/tests/ui/borrowck/non-promotable-static-ref.stderr similarity index 90% rename from tests/ui/issues/issue-52049.stderr rename to tests/ui/borrowck/non-promotable-static-ref.stderr index 1d8e136f217b0..979b349b7c005 100644 --- a/tests/ui/issues/issue-52049.stderr +++ b/tests/ui/borrowck/non-promotable-static-ref.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-52049.rs:6:10 + --> $DIR/non-promotable-static-ref.rs:8:10 | LL | foo(&unpromotable(5u32)); | -----^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index e64e60f30c0c1..09c2a05cd009f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -26,12 +26,15 @@ impl Bar for i32 {} // cannot use special rustc_on_unimplement symbols // in the format string #[diagnostic::on_unimplemented( - message = "{from_desugaring}{direct}{cause}{integral}{integer}", + message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", //~^WARN there is no parameter `from_desugaring` on trait `Baz` //~|WARN there is no parameter `direct` on trait `Baz` //~|WARN there is no parameter `cause` on trait `Baz` //~|WARN there is no parameter `integral` on trait `Baz` //~|WARN there is no parameter `integer` on trait `Baz` + //~|WARN there is no parameter `r#struct` on trait `Baz` + //~|WARN there is no parameter `r#enum` on trait `Baz` + //~|WARN there is no parameter `union` on trait `Baz` label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" //~^WARN there is no parameter `float` on trait `Baz` //~|WARN there is no parameter `_Self` on trait `Baz` @@ -52,5 +55,5 @@ fn main() { takes_bar(()); //~^ERROR the trait bound `(): Bar` is not satisfied takes_baz(()); - //~^ERROR {from_desugaring}{direct}{cause}{integral}{integer} + //~^ERROR {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union} } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index 862f805e15ba7..58d2bdbfc4d6e 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -9,7 +9,7 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl warning: there is no parameter `from_desugaring` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:17 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -18,7 +18,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `direct` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:34 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -26,7 +26,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `cause` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:42 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -34,7 +34,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `integral` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:49 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -42,13 +42,37 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `integer` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:59 | -LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", | ^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument +warning: there is no parameter `r#struct` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:68 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", + | ^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `r#enum` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:76 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", + | ^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +warning: there is no parameter `union` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:82 + | +LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union}", + | ^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:15 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ @@ -56,7 +80,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:22 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ @@ -64,7 +88,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:29 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:29 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ @@ -72,7 +96,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:42 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:42 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ @@ -80,7 +104,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:49 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:49 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ @@ -88,7 +112,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `This` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:35:62 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:38:62 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^ @@ -129,7 +153,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = help: only `message`, `note` and `label` are allowed as options error[E0277]: trait has `()` and `i32` as params - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:53:15 | LL | takes_foo(()); | --------- ^^ trait has `()` and `i32` as params @@ -144,13 +168,13 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:45:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:48:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^^^^^^ required by this bound in `takes_foo` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:15 | LL | takes_bar(()); | --------- ^^ the trait `Bar` is not implemented for `()` @@ -163,13 +187,13 @@ help: the trait `Bar` is implemented for `i32` LL | impl Bar for i32 {} | ^^^^^^^^^^^^^^^^ note: required by a bound in `takes_bar` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:49:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` -error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer} - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:15 +error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}{struct}{enum}{union} + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:57:15 | LL | takes_baz(()); | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}{This} @@ -178,16 +202,16 @@ LL | takes_baz(()); | = help: the trait `Baz` is not implemented for `()` help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:43:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:46:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `takes_baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:47:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:50:22 | LL | fn takes_baz(_: impl Baz) {} | ^^^ required by this bound in `takes_baz` -error: aborting due to 3 previous errors; 16 warnings emitted +error: aborting due to 3 previous errors; 19 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/macros/attr-expr.rs b/tests/ui/macros/attr-expr.rs new file mode 100644 index 0000000000000..a2bee8728ac57 --- /dev/null +++ b/tests/ui/macros/attr-expr.rs @@ -0,0 +1,19 @@ +macro_rules! foo { + ($e:expr) => { + #[$e] + //~^ ERROR expected identifier, found metavariable + fn foo() {} + }; +} +foo!(inline); + +macro_rules! bar { + ($e:expr) => { + #[inline($e)] + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable + fn bar() {} + }; +} +bar!(always); + +fn main() {} diff --git a/tests/ui/macros/attr-expr.stderr b/tests/ui/macros/attr-expr.stderr new file mode 100644 index 0000000000000..eaad41c44fb9a --- /dev/null +++ b/tests/ui/macros/attr-expr.stderr @@ -0,0 +1,24 @@ +error: expected identifier, found metavariable + --> $DIR/attr-expr.rs:3:11 + | +LL | #[$e] + | ^^ expected identifier, found metavariable +... +LL | foo!(inline); + | ------------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable + --> $DIR/attr-expr.rs:12:18 + | +LL | #[inline($e)] + | ^^ +... +LL | bar!(always); + | ------------ in this macro invocation + | + = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/cfg-expr.rs b/tests/ui/macros/cfg-expr.rs new file mode 100644 index 0000000000000..e9ca6e3d7b10c --- /dev/null +++ b/tests/ui/macros/cfg-expr.rs @@ -0,0 +1,44 @@ +//@ run-pass +macro_rules! foo { + ($e:expr, $n:ident) => { + #[cfg($e)] + macro_rules! $n { + () => {} + } + + #[cfg_attr($e, allow(non_snake_case))] + #[cfg($e)] + fn $n() { + #[cfg($e)] + $n!(); + } + + #[cfg_attr(not($e), allow(unused))] + #[cfg(not($e))] + fn $n() { + panic!() + } + } +} +foo!(true, BAR); +foo!(any(true, unix, target_pointer_width = "64"), baz); +foo!(target_pointer_width = "64", quux); +foo!(false, haha); + +fn main() { + BAR(); + BAR!(); + baz(); + baz!(); + #[cfg(target_pointer_width = "64")] + quux(); + #[cfg(target_pointer_width = "64")] + quux!(); + #[cfg(panic = "unwind")] + { + let result = std::panic::catch_unwind(|| { + haha(); + }); + assert!(result.is_err()); + } +} diff --git a/tests/ui/macros/cfg_attr-expr.rs b/tests/ui/macros/cfg_attr-expr.rs new file mode 100644 index 0000000000000..1dab2cae59fa7 --- /dev/null +++ b/tests/ui/macros/cfg_attr-expr.rs @@ -0,0 +1,9 @@ +macro_rules! foo { + ($e:expr) => { + #[cfg_attr(true, $e)] + //~^ ERROR expected identifier, found metavariable + fn foo() {} + } +} +foo!(inline); +fn main() {} diff --git a/tests/ui/macros/cfg_attr-expr.stderr b/tests/ui/macros/cfg_attr-expr.stderr new file mode 100644 index 0000000000000..a46ea104b9398 --- /dev/null +++ b/tests/ui/macros/cfg_attr-expr.stderr @@ -0,0 +1,17 @@ +error: expected identifier, found metavariable + --> $DIR/cfg_attr-expr.rs:3:26 + | +LL | #[cfg_attr(true, $e)] + | -----------------^^-- + | | | + | | expected identifier, found metavariable + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` +... +LL | foo!(inline); + | ------------ in this macro invocation + | + = note: for more information, visit + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/cfg_select-expr.rs b/tests/ui/macros/cfg_select-expr.rs new file mode 100644 index 0000000000000..90e894562a16b --- /dev/null +++ b/tests/ui/macros/cfg_select-expr.rs @@ -0,0 +1,57 @@ +//@ run-pass +#![allow(unreachable_cfg_select_predicates)] + +macro_rules! foo { + ($e:expr, $n:ident) => { + cfg_select! { + $e => { + macro_rules! $n { + () => {} + } + } + _ => {} + } + + cfg_select! { + $e => { + #[cfg_attr($e, allow(non_snake_case))] + fn $n() { + cfg_select! { + $e => { + $n!(); + } + _ => {} + } + } + } + not($e) => { + #[cfg_attr(not($e), allow(unused))] + fn $n() { + panic!() + } + } + } + } +} +foo!(true, BAR); +foo!(any(true, unix, target_pointer_width = "64"), baz); +foo!(target_pointer_width = "64", quux); +foo!(false, haha); + +fn main() { + BAR(); + BAR!(); + baz(); + baz!(); + #[cfg(target_pointer_width = "64")] + quux(); + #[cfg(target_pointer_width = "64")] + quux!(); + #[cfg(panic = "unwind")] + { + let result = std::panic::catch_unwind(|| { + haha(); + }); + assert!(result.is_err()); + } +} diff --git a/tests/ui/on-unimplemented/self-types.rs b/tests/ui/on-unimplemented/self-types.rs new file mode 100644 index 0000000000000..736d3baf60c78 --- /dev/null +++ b/tests/ui/on-unimplemented/self-types.rs @@ -0,0 +1,30 @@ +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented( + on(Self = "{union}", message = "union self type"), + on(Self = "{enum}", message = "enum self type"), + on(Self = "{struct}", message = "struct self type"), + message = "fallback self type `{Self}`" +)] +trait Trait {} + +union Union { + value: u8, +} + +enum Enum { + Variant, +} + +struct Struct; + +fn needs_trait() {} + +fn main() { + needs_trait::(); + //~^ ERROR union self type + needs_trait::(); + //~^ ERROR enum self type + needs_trait::(); + //~^ ERROR struct self type +} diff --git a/tests/ui/on-unimplemented/self-types.stderr b/tests/ui/on-unimplemented/self-types.stderr new file mode 100644 index 0000000000000..ea40ac566bb91 --- /dev/null +++ b/tests/ui/on-unimplemented/self-types.stderr @@ -0,0 +1,69 @@ +error[E0277]: union self type + --> $DIR/self-types.rs:24:19 + | +LL | needs_trait::(); + | ^^^^^ unsatisfied trait bound + | +help: the trait `Trait` is not implemented for `Union` + --> $DIR/self-types.rs:11:1 + | +LL | union Union { + | ^^^^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/self-types.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/self-types.rs:21:19 + | +LL | fn needs_trait() {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: enum self type + --> $DIR/self-types.rs:26:19 + | +LL | needs_trait::(); + | ^^^^ unsatisfied trait bound + | +help: the trait `Trait` is not implemented for `Enum` + --> $DIR/self-types.rs:15:1 + | +LL | enum Enum { + | ^^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/self-types.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/self-types.rs:21:19 + | +LL | fn needs_trait() {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: struct self type + --> $DIR/self-types.rs:28:19 + | +LL | needs_trait::(); + | ^^^^^^ unsatisfied trait bound + | +help: the trait `Trait` is not implemented for `Struct` + --> $DIR/self-types.rs:19:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ +help: this trait has no implementations, consider adding one + --> $DIR/self-types.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/self-types.rs:21:19 + | +LL | fn needs_trait() {} + | ^^^^^ required by this bound in `needs_trait` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr index 45f39fefe5e34..56c78b01ea390 100644 --- a/tests/ui/parser/recover/array-type-no-semi.stderr +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -17,7 +17,12 @@ LL | let a: [i32, ]; | - ^ expected `;` or `]` | | | while parsing the type for `a` - | help: use `=` if you meant to assign + | +help: use `=` if you meant to assign + | +LL - let a: [i32, ]; +LL + let a = [i32, ]; + | error: expected `;` or `]`, found `,` --> $DIR/array-type-no-semi.rs:12:16 diff --git a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr index 15c27bb9451b6..94e5d44064f8c 100644 --- a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr +++ b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr @@ -13,7 +13,12 @@ LL | let _: std::env::temp_dir().join("foo"); | - ^ expected one of `!`, `+`, `->`, `::`, `;`, or `=` | | | while parsing the type for `_` - | help: use `=` if you meant to assign + | +help: use `=` if you meant to assign + | +LL - let _: std::env::temp_dir().join("foo"); +LL + let _ = std::env::temp_dir().join("foo"); + | error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs index 71e5a0c728d6b..c108b567b18b5 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs @@ -1,11 +1,41 @@ -pub fn foo(num: i32) -> i32 { +fn foo(num: i32) -> i32 { + // FIXME: This case doesn't really check that `from_be` is a valid function in `i32`. let foo: i32::from_be(num); //~^ ERROR expected type, found local variable `num` - //~| ERROR argument types not allowed with return type notation - //~| ERROR return type notation not allowed in this position yet + //~| ERROR expected type, found associated function call foo } +struct S; + +impl S { + fn new(_: ()) -> S { + S + } +} + +// We should still mention that it should be `S::new(..)`, even though rtn is not allowed there: +struct K(S::new(())); //~ ERROR return type notation not allowed in this position yet + +fn bar() {} + fn main() { let _ = foo(42); + // Associated functions (#134087) + let x: Vec::new(); //~ ERROR expected type, found associated function call + let x: Vec<()>::new(); //~ ERROR expected type, found associated function call + let x: S::new(..); //~ ERROR expected type, found associated function call + //~^ ERROR return type notation is experimental + let x: S::new(()); //~ ERROR expected type, found associated function call + + // Literals + let x: 42; //~ ERROR expected type, found `42` + let x: ""; //~ ERROR expected type, found `""` + + // Functions + let x: bar(); //~ ERROR expected type, found function `bar` + let x: bar; //~ ERROR expected type, found function `bar` + + // Locals + let x: x; //~ ERROR expected type, found local variable `x` } diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index 19a0e4b17d029..354d119769119 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -1,32 +1,159 @@ +error: expected type, found `42` + --> $DIR/let-binding-init-expr-as-ty.rs:32:12 + | +LL | let x: 42; + | - ^^ expected type + | | + | while parsing the type for `x` + | +help: use `=` if you meant to assign + | +LL - let x: 42; +LL + let x = 42; + | + +error: expected type, found `""` + --> $DIR/let-binding-init-expr-as-ty.rs:33:12 + | +LL | let x: ""; + | - ^^ expected type + | | + | while parsing the type for `x` + | +help: use `=` if you meant to assign + | +LL - let x: ""; +LL + let x = ""; + | + error[E0573]: expected type, found local variable `num` - --> $DIR/let-binding-init-expr-as-ty.rs:2:27 + --> $DIR/let-binding-init-expr-as-ty.rs:3:27 | LL | let foo: i32::from_be(num); - | -- ^^^ not a type - | | - | help: use `=` if you meant to assign + | ^^^ not a type + | +help: use `=` if you meant to assign + | +LL - let foo: i32::from_be(num); +LL + let foo = i32::from_be(num); + | -error: argument types not allowed with return type notation - --> $DIR/let-binding-init-expr-as-ty.rs:2:26 +error[E0573]: expected type, found function `bar` + --> $DIR/let-binding-init-expr-as-ty.rs:36:12 | -LL | let foo: i32::from_be(num); - | ^^^^^ +LL | let x: bar(); + | ^^^^^ not a type + | +help: use `=` if you meant to assign + | +LL - let x: bar(); +LL + let x = bar(); + | + +error[E0573]: expected type, found function `bar` + --> $DIR/let-binding-init-expr-as-ty.rs:37:12 + | +LL | let x: bar; + | ^^^ not a type + +error[E0573]: expected type, found local variable `x` + --> $DIR/let-binding-init-expr-as-ty.rs:40:12 + | +LL | struct K(S::new(())); + | --------------------- similarly named struct `K` defined here +... +LL | let x: x; + | ^ + | +help: a struct with a similar name exists + | +LL - let x: x; +LL + let x: K; + | + +error[E0658]: return type notation is experimental + --> $DIR/let-binding-init-expr-as-ty.rs:27:18 + | +LL | let x: S::new(..); + | ^^^^ | = note: see issue #109417 for more information = help: add `#![feature(return_type_notation)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -help: remove the input types + +error: return type notation not allowed in this position yet + --> $DIR/let-binding-init-expr-as-ty.rs:18:10 | -LL - let foo: i32::from_be(num); -LL + let foo: i32::from_be(..); +LL | struct K(S::new(())); + | ^^^^^^^^^^ + | +help: furthermore, argument types not allowed with return type notation + | +LL - struct K(S::new(())); +LL + struct K(S::new(..)); | -error: return type notation not allowed in this position yet - --> $DIR/let-binding-init-expr-as-ty.rs:2:14 +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:3:14 | LL | let foo: i32::from_be(num); | ^^^^^^^^^^^^^^^^^ + | +help: use `=` if you meant to assign + | +LL - let foo: i32::from_be(num); +LL + let foo = i32::from_be(num); + | + +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:25:12 + | +LL | let x: Vec::new(); + | ^^^^^^^^^^ + | +help: use `=` if you meant to assign + | +LL - let x: Vec::new(); +LL + let x = Vec::new(); + | + +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:26:12 + | +LL | let x: Vec<()>::new(); + | ^^^^^^^^^^^^^^ + | +help: use `=` if you meant to assign + | +LL - let x: Vec<()>::new(); +LL + let x = Vec<()>::new(); + | + +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:27:12 + | +LL | let x: S::new(..); + | ^^^^^^^^^^ + | +help: use `=` if you meant to assign + | +LL - let x: S::new(..); +LL + let x = S::new(..); + | + +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:29:12 + | +LL | let x: S::new(()); + | ^^^^^^^^^^ + | +help: use `=` if you meant to assign + | +LL - let x: S::new(()); +LL + let x = S::new(()); + | -error: aborting due to 3 previous errors +error: aborting due to 13 previous errors -For more information about this error, try `rustc --explain E0573`. +Some errors have detailed explanations: E0573, E0658. +For more information about an error, try `rustc --explain E0573`. diff --git a/tests/ui/type/type-ascription-instead-of-initializer.stderr b/tests/ui/type/type-ascription-instead-of-initializer.stderr index 630e82d254eed..edc38b0ca7b91 100644 --- a/tests/ui/type/type-ascription-instead-of-initializer.stderr +++ b/tests/ui/type/type-ascription-instead-of-initializer.stderr @@ -5,7 +5,12 @@ LL | let x: Vec::with_capacity(10, 20); | - ^^ expected type | | | while parsing the type for `x` - | help: use `=` if you meant to assign + | +help: use `=` if you meant to assign + | +LL - let x: Vec::with_capacity(10, 20); +LL + let x = Vec::with_capacity(10, 20); + | error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 diff --git a/tests/ui/union/union-no-derive-suggestion.rs b/tests/ui/union/union-no-derive-suggestion.rs new file mode 100644 index 0000000000000..0ccbac3167f2e --- /dev/null +++ b/tests/ui/union/union-no-derive-suggestion.rs @@ -0,0 +1,37 @@ +//! Check that we do not suggest using `#[derive(...)]` for unions, +//! as some traits cannot be autoderived for them. +//@ dont-require-annotations: NOTE + +union U { //~ HELP consider annotating `U` with `#[derive(Clone)]` + //~| HELP consider annotating `U` with `#[derive(Copy)]` + //~| HELP the trait `Debug` is not implemented for `U` + //~| HELP the trait `Default` is not implemented for `U` + //~| HELP the trait `Hash` is not implemented for `U` + a: u8, +} + +fn x() {} +fn y() {} + +fn main() { + let u = U { a: 0 }; + // Debug + println!("{u:?}"); //~ ERROR `U` doesn't implement `Debug` + //~| NOTE manually `impl Debug for U` + // PartialEq + let _ = u == U { a: 0 }; //~ ERROR binary operation `==` cannot be applied to type `U` + //~| NOTE the trait `PartialEq` must be implemented + // PartialOrd + let _ = u < U { a: 1 }; //~ ERROR binary operation `<` cannot be applied to type `U` + //~| NOTE the trait `PartialOrd` must be implemented + // Default + let _: U = Default::default(); //~ ERROR the trait bound `U: Default` is not satisfied + // Hash + let mut h = std::collections::hash_map::DefaultHasher::new(); + std::hash::Hash::hash(&u, &mut h); //~ ERROR the trait bound `U: Hash` is not satisfied + + // Clone + x::(); //~ ERROR the trait bound `U: Clone` is not satisfied + // Copy + y::(); //~ ERROR the trait bound `U: Copy` is not satisfied +} diff --git a/tests/ui/union/union-no-derive-suggestion.stderr b/tests/ui/union/union-no-derive-suggestion.stderr new file mode 100644 index 0000000000000..7a42b871b80d6 --- /dev/null +++ b/tests/ui/union/union-no-derive-suggestion.stderr @@ -0,0 +1,109 @@ +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/union-no-derive-suggestion.rs:19:15 + | +LL | println!("{u:?}"); + | ^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: the trait `Debug` is not implemented for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ + = note: manually `impl Debug for U` + +error[E0369]: binary operation `==` cannot be applied to type `U` + --> $DIR/union-no-derive-suggestion.rs:22:15 + | +LL | let _ = u == U { a: 0 }; + | - ^^ ---------- U + | | + | U + | +note: an implementation of `PartialEq` might be missing for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ must implement `PartialEq` +note: the trait `PartialEq` must be implemented + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error[E0369]: binary operation `<` cannot be applied to type `U` + --> $DIR/union-no-derive-suggestion.rs:25:15 + | +LL | let _ = u < U { a: 1 }; + | - ^ ---------- U + | | + | U + | +note: an implementation of `PartialOrd` might be missing for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ must implement `PartialOrd` +note: the trait `PartialOrd` must be implemented + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error[E0277]: the trait bound `U: Default` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:28:16 + | +LL | let _: U = Default::default(); + | ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `Default` is not implemented for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ + +error[E0277]: the trait bound `U: Hash` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:31:27 + | +LL | std::hash::Hash::hash(&u, &mut h); + | --------------------- ^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `Hash` is not implemented for `U` + --> $DIR/union-no-derive-suggestion.rs:5:1 + | +LL | union U { + | ^^^^^^^ + +error[E0277]: the trait bound `U: Clone` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:34:9 + | +LL | x::(); + | ^ the trait `Clone` is not implemented for `U` + | +note: required by a bound in `x` + --> $DIR/union-no-derive-suggestion.rs:13:9 + | +LL | fn x() {} + | ^^^^^ required by this bound in `x` +help: consider annotating `U` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | union U { + | + +error[E0277]: the trait bound `U: Copy` is not satisfied + --> $DIR/union-no-derive-suggestion.rs:36:9 + | +LL | y::(); + | ^ the trait `Copy` is not implemented for `U` + | +note: required by a bound in `y` + --> $DIR/union-no-derive-suggestion.rs:14:9 + | +LL | fn y() {} + | ^^^^ required by this bound in `y` +help: consider annotating `U` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | union U { + | + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`.