diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e8823eff83afe..feb5187536ffa 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -400,8 +400,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref); visitor.visit_ty(&mutable_type.ty) } - TyKind::Tup(tuple_element_types) => { - walk_list!(visitor, visit_ty, tuple_element_types); + TyKind::Tup(tys) => { + walk_list!(visitor, visit_ty, tys); } TyKind::BareFn(function_declaration) => { walk_list!(visitor, visit_generic_param, &function_declaration.generic_params); diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 91857dd227ddd..0c2ab3d08f9de 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -710,3 +710,24 @@ passes_ignored_derived_impls = [one] trait {$trait_list}, but this is *[other] traits {$trait_list}, but these are } intentionally ignored during dead code analysis + +passes_proc_macro_typeerror = mismatched {$kind} signature + .label = found {$found}, expected type `proc_macro::TokenStream` + .note = {$kind}s must have a signature of `{$expected_signature}` + +passes_proc_macro_diff_arg_count = mismatched {$kind} signature + .label = found unexpected {$count -> + [one] argument + *[other] arguments + } + .note = {$kind}s must have a signature of `{$expected_signature}` + +passes_proc_macro_missing_args = mismatched {$kind} signature + .label = {$kind} must have {$expected_input_count -> + [one] one argument + *[other] two arguments + } of type `proc_macro::TokenStream` + +passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"` + +passes_proc_macro_unsafe = proc macro functions may not be `unsafe` diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index bbf7b81a2cc66..d5f37abb8b455 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1619,6 +1619,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } } + fn note_unreachable_loop_return( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index bd1626dff7951..3e9b04c2c0b9c 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -59,9 +59,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) || self.suggest_clone_for_ref(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) - || self.suggest_floating_point_literal(err, expr, expected); + || self.suggest_floating_point_literal(err, expr, expected) + || self.note_result_coercion(err, expr, expected, expr_ty); if !suggested { - self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected); + self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span); } } @@ -222,6 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, found: Ty<'tcx>, expected: Ty<'tcx>, + mismatch_span: Span, ) -> bool { let map = self.tcx.hir(); @@ -270,7 +272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lt_op: |_| self.tcx.lifetimes.re_erased, ct_op: |c| c, ty_op: |t| match *t.kind() { - ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))), + ty::Infer(ty::TyVar(_)) => self.tcx.mk_ty_var(ty::TyVid::from_u32(0)), ty::Infer(ty::IntVar(_)) => { self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 })) } @@ -281,7 +283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; let mut prev = eraser.fold_ty(ty); - let mut prev_span = None; + let mut prev_span: Option = None; for binding in expr_finder.uses { // In every expression where the binding is referenced, we will look at that @@ -333,13 +335,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inferred in this method call. let arg = &args[i]; let arg_ty = self.node_ty(arg.hir_id); - err.span_label( - arg.span, - &format!( - "this is of type `{arg_ty}`, which causes `{ident}` to be \ - inferred as `{ty}`", - ), - ); + if !arg.span.overlaps(mismatch_span) { + err.span_label( + arg.span, + &format!( + "this is of type `{arg_ty}`, which causes `{ident}` to be \ + inferred as `{ty}`", + ), + ); + } param_args.insert(param_ty, (arg, arg_ty)); } } @@ -382,12 +386,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.can_eq(self.param_env, ty, found).is_ok() { // We only point at the first place where the found type was inferred. + if !segment.ident.span.overlaps(mismatch_span) { err.span_label( segment.ident.span, with_forced_trimmed_paths!(format!( "here the type of `{ident}` is inferred to be `{ty}`", )), - ); + );} break; } else if !param_args.is_empty() { break; @@ -406,12 +411,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We use the *previous* span because if the type is known *here* it means // it was *evaluated earlier*. We don't do this for method calls because we // evaluate the method's self type eagerly, but not in any other case. - err.span_label( - span, - with_forced_trimmed_paths!(format!( - "here the type of `{ident}` is inferred to be `{ty}`", - )), - ); + if !span.overlaps(mismatch_span) { + err.span_label( + span, + with_forced_trimmed_paths!(format!( + "here the type of `{ident}` is inferred to be `{ty}`", + )), + ); + } break; } prev = ty; @@ -697,6 +704,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + pub(crate) fn note_result_coercion( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + let ty::Adt(e, substs_e) = expected.kind() else { return false; }; + let ty::Adt(f, substs_f) = found.kind() else { return false; }; + if e.did() != f.did() { + return false; + } + if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) { + return false; + } + let map = self.tcx.hir(); + if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id) + && let hir::ExprKind::Ret(_) = expr.kind + { + // `return foo;` + } else if map.get_return_block(expr.hir_id).is_some() { + // Function's tail expression. + } else { + return false; + } + let e = substs_e.type_at(1); + let f = substs_f.type_at(1); + if self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::Into).unwrap(), + [f, e], + self.param_env, + ) + .must_apply_modulo_regions() + { + err.multipart_suggestion( + "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \ + in `Ok` so the expression remains of type `Result`", + vec![ + (expr.span.shrink_to_lo(), "Ok(".to_string()), + (expr.span.shrink_to_hi(), "?)".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return true; + } + false + } + /// If the expected type is an enum (Issue #55250) with any variants whose /// sole field is of the found type, suggest such variants. (Issue #42764) fn suggest_compatible_variants( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c9609e6943981..677c80297b912 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -808,7 +808,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::MiscVariable, span: full_call_span, }); - self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty); + self.point_at_expr_source_of_inferred_type( + &mut err, + rcvr, + expected, + callee_ty, + provided_arg_span, + ); } // Call out where the function is defined self.label_fn_like( diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 0bca02589bce1..9840b95feefde 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -147,6 +147,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ExprKind::AddressOf { mutability, arg } => Ok( Rvalue::AddressOf(*mutability, self.parse_place(*arg)?) ), + ExprKind::Binary { op, lhs, rhs } => Ok( + Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))) + ), + ExprKind::Unary { op, arg } => Ok( + Rvalue::UnaryOp(*op, self.parse_operand(*arg)?) + ), _ => self.parse_operand(expr_id).map(Rvalue::Use), ) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4c918c6702ed9..eda7046c748e5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2372,7 +2372,7 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - pub(crate) fn maybe_recover_colon_colon_in_pat_typo( + pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum( &mut self, mut first_pat: P, expected: Expected, @@ -2383,26 +2383,41 @@ impl<'a> Parser<'a> { if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) { + let mut snapshot_type = self.create_snapshot_for_diagnostic(); + snapshot_type.bump(); // `:` + match snapshot_type.parse_ty() { + Err(inner_err) => { + inner_err.cancel(); + } + Ok(ty) => { + let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else { + return first_pat; + }; + err.span_label(ty.span, "specifying the type of a pattern isn't supported"); + self.restore_snapshot(snapshot_type); + let span = first_pat.span.to(ty.span); + first_pat = self.mk_pat(span, PatKind::Wild); + err.emit(); + } + } return first_pat; } // The pattern looks like it might be a path with a `::` -> `:` typo: // `match foo { bar:baz => {} }` - let span = self.token.span; + let colon_span = self.token.span; // We only emit "unexpected `:`" error here if we can successfully parse the // whole pattern correctly in that case. - let snapshot = self.create_snapshot_for_diagnostic(); + let mut snapshot_pat = self.create_snapshot_for_diagnostic(); + let mut snapshot_type = self.create_snapshot_for_diagnostic(); // Create error for "unexpected `:`". match self.expected_one_of_not_found(&[], &[]) { Err(mut err) => { - self.bump(); // Skip the `:`. - match self.parse_pat_no_top_alt(expected) { + snapshot_pat.bump(); // Skip the `:`. + snapshot_type.bump(); // Skip the `:`. + match snapshot_pat.parse_pat_no_top_alt(expected) { Err(inner_err) => { - // Carry on as if we had not done anything, callers will emit a - // reasonable error. inner_err.cancel(); - err.cancel(); - self.restore_snapshot(snapshot); } Ok(mut pat) => { // We've parsed the rest of the pattern. @@ -2466,8 +2481,8 @@ impl<'a> Parser<'a> { _ => {} } if show_sugg { - err.span_suggestion( - span, + err.span_suggestion_verbose( + colon_span.until(self.look_ahead(1, |t| t.span)), "maybe write a path separator here", "::", Applicability::MaybeIncorrect, @@ -2475,13 +2490,24 @@ impl<'a> Parser<'a> { } else { first_pat = self.mk_pat(new_span, PatKind::Wild); } - err.emit(); + self.restore_snapshot(snapshot_pat); } } + match snapshot_type.parse_ty() { + Err(inner_err) => { + inner_err.cancel(); + } + Ok(ty) => { + err.span_label(ty.span, "specifying the type of a pattern isn't supported"); + self.restore_snapshot(snapshot_type); + let new_span = first_pat.span.to(ty.span); + first_pat = self.mk_pat(new_span, PatKind::Wild); + } + } + err.emit(); } _ => { // Carry on as if we had not done anything. This should be unreachable. - self.restore_snapshot(snapshot); } }; first_pat diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index e73a17ced7deb..e5411538eea22 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -116,7 +116,8 @@ impl<'a> Parser<'a> { // Check if the user wrote `foo:bar` instead of `foo::bar`. if ra == RecoverColon::Yes { - first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected); + first_pat = + self.maybe_recover_colon_colon_in_pat_typo_or_anon_enum(first_pat, expected); } if let Some(leading_vert_span) = leading_vert_span { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1766b0293de52..25de0a9e75014 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -11,6 +11,7 @@ use rustc_ast::{ self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind, }; +use rustc_ast_pretty::pprust; use rustc_errors::{pluralize, struct_span_err, Applicability, PResult}; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident}; @@ -43,17 +44,24 @@ pub(super) enum AllowPlus { No, } -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub(super) enum RecoverQPath { Yes, No, } +#[derive(PartialEq, Clone, Copy)] pub(super) enum RecoverQuestionMark { Yes, No, } +#[derive(PartialEq, Clone, Copy)] +pub(super) enum RecoverAnonEnum { + Yes, + No, +} + /// Signals whether parsing a type should recover `->`. /// /// More specifically, when parsing a function like: @@ -86,7 +94,7 @@ impl RecoverReturnSign { } // Is `...` (`CVarArgs`) legal at this level of type parsing? -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] enum AllowCVariadic { Yes, No, @@ -111,6 +119,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -125,6 +134,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, Some(ty_params), RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -139,6 +149,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::Yes, ) } @@ -156,6 +167,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -169,6 +181,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::No, + RecoverAnonEnum::No, ) } @@ -180,6 +193,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::No, + RecoverAnonEnum::No, ) } @@ -192,6 +206,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::OnlyFatArrow, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -211,6 +226,7 @@ impl<'a> Parser<'a> { recover_return_sign, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::Yes, )?; FnRetTy::Ty(ty) } else if recover_return_sign.can_recover(&self.token.kind) { @@ -232,6 +248,7 @@ impl<'a> Parser<'a> { recover_return_sign, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::Yes, )?; FnRetTy::Ty(ty) } else { @@ -247,6 +264,7 @@ impl<'a> Parser<'a> { recover_return_sign: RecoverReturnSign, ty_generics: Option<&Generics>, recover_question_mark: RecoverQuestionMark, + recover_anon_enum: RecoverAnonEnum, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); @@ -325,14 +343,55 @@ impl<'a> Parser<'a> { let mut ty = self.mk_ty(span, kind); // Try to recover from use of `+` with incorrect priority. - if matches!(allow_plus, AllowPlus::Yes) { + if allow_plus == AllowPlus::Yes { self.maybe_recover_from_bad_type_plus(&ty)?; } else { self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty); } - if let RecoverQuestionMark::Yes = recover_question_mark { + if RecoverQuestionMark::Yes == recover_question_mark { ty = self.maybe_recover_from_question_mark(ty); } + if recover_anon_enum == RecoverAnonEnum::Yes + && self.check_noexpect(&token::BinOp(token::Or)) + && self.look_ahead(1, |t| t.can_begin_type()) + { + let mut pipes = vec![self.token.span]; + let mut types = vec![ty]; + loop { + if !self.eat(&token::BinOp(token::Or)) { + break; + } + pipes.push(self.prev_token.span); + types.push(self.parse_ty_common( + allow_plus, + allow_c_variadic, + recover_qpath, + recover_return_sign, + ty_generics, + recover_question_mark, + RecoverAnonEnum::No, + )?); + } + let mut err = self.struct_span_err(pipes, "anonymous enums are not supported"); + for ty in &types { + err.span_label(ty.span, ""); + } + err.help(&format!( + "create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}", + types + .iter() + .enumerate() + .map(|(i, t)| format!( + " Variant{}({}),", + i + 1, // Lets not confuse people with zero-indexing :) + pprust::to_string(|s| s.print_type(&t)), + )) + .collect::>() + .join("\n"), + )); + err.emit(); + return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::Err)); + } if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f9f9799d3e4f2..4232985325945 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -6,11 +6,12 @@ use crate::errors::{ self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr, - OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint, + OnlyHasEffectOn, ProcMacroDiffArguments, ProcMacroInvalidAbi, ProcMacroMissingArguments, + ProcMacroTypeError, ProcMacroUnsafe, TransparentIncompatible, UnrecognizedReprHint, }; use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{fluent, Applicability, MultiSpan}; +use rustc_errors::{fluent, Applicability, IntoDiagnosticArg, MultiSpan}; use rustc_expand::base::resolve_path; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; @@ -19,11 +20,12 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, }; -use rustc_hir::{MethodKind, Target}; +use rustc_hir::{MethodKind, Target, Unsafety}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{ParamEnv, TyCtxt}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; @@ -31,6 +33,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use std::cell::Cell; use std::collections::hash_map::Entry; pub(crate) fn target_from_impl_item<'tcx>( @@ -62,8 +65,29 @@ enum ItemLike<'tcx> { ForeignItem, } +#[derive(Copy, Clone)] +pub(crate) enum ProcMacroKind { + FunctionLike, + Derive, + Attribute, +} + +impl IntoDiagnosticArg for ProcMacroKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + match self { + ProcMacroKind::Attribute => "attribute proc macro", + ProcMacroKind::Derive => "derive proc macro", + ProcMacroKind::FunctionLike => "function-like proc macro", + } + .into_diagnostic_arg() + } +} + struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, + + // Whether or not this visitor should abort after finding errors + abort: Cell, } impl CheckAttrVisitor<'_> { @@ -173,7 +197,7 @@ impl CheckAttrVisitor<'_> { sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod), sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target), sym::macro_export => self.check_macro_export(hir_id, attr, target), - sym::ignore | sym::should_panic | sym::proc_macro_derive => { + sym::ignore | sym::should_panic => { self.check_generic_attr(hir_id, attr, target, Target::Fn) } sym::automatically_derived => { @@ -183,6 +207,16 @@ impl CheckAttrVisitor<'_> { self.check_generic_attr(hir_id, attr, target, Target::Mod) } sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id), + sym::proc_macro => { + self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) + } + sym::proc_macro_attribute => { + self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); + } + sym::proc_macro_derive => { + self.check_generic_attr(hir_id, attr, target, Target::Fn); + self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) + } _ => {} } @@ -2063,6 +2097,103 @@ impl CheckAttrVisitor<'_> { errors::Unused { attr_span: attr.span, note }, ); } + + /// A best effort attempt to create an error for a mismatching proc macro signature. + /// + /// If this best effort goes wrong, it will just emit a worse error later (see #102923) + fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) { + let expected_input_count = match kind { + ProcMacroKind::Attribute => 2, + ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1, + }; + + let expected_signature = match kind { + ProcMacroKind::Attribute => "fn(TokenStream, TokenStream) -> TokenStream", + ProcMacroKind::Derive | ProcMacroKind::FunctionLike => "fn(TokenStream) -> TokenStream", + }; + + let tcx = self.tcx; + if target == Target::Fn { + let Some(tokenstream) = tcx.get_diagnostic_item(sym::TokenStream) else {return}; + let tokenstream = tcx.type_of(tokenstream); + + let id = hir_id.expect_owner(); + let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap(); + + let sig = tcx.liberate_late_bound_regions(id.to_def_id(), tcx.fn_sig(id)); + let sig = tcx.normalize_erasing_regions(ParamEnv::empty(), sig); + + // We don't currently require that the function signature is equal to + // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to + // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments. + // + // Properly checking this means pulling in additional `rustc` crates, so we don't. + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }; + + if sig.abi != Abi::Rust { + tcx.sess.emit_err(ProcMacroInvalidAbi { span: hir_sig.span, abi: sig.abi.name() }); + self.abort.set(true); + } + + if sig.unsafety == Unsafety::Unsafe { + tcx.sess.emit_err(ProcMacroUnsafe { span: hir_sig.span }); + self.abort.set(true); + } + + let output = sig.output(); + + // Typecheck the output + if !drcx.types_may_unify(output, tokenstream) { + tcx.sess.emit_err(ProcMacroTypeError { + span: hir_sig.decl.output.span(), + found: output, + kind, + expected_signature, + }); + self.abort.set(true); + } + + if sig.inputs().len() < expected_input_count { + tcx.sess.emit_err(ProcMacroMissingArguments { + expected_input_count, + span: hir_sig.span, + kind, + expected_signature, + }); + self.abort.set(true); + } + + // Check that the inputs are correct, if there are enough. + if sig.inputs().len() >= expected_input_count { + for (arg, input) in + sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count) + { + if !drcx.types_may_unify(*arg, tokenstream) { + tcx.sess.emit_err(ProcMacroTypeError { + span: input.span, + found: *arg, + kind, + expected_signature, + }); + self.abort.set(true); + } + } + } + + // Check that there are not too many arguments + let body_id = tcx.hir().body_owned_by(id.def_id); + let excess = tcx.hir().body(body_id).params.get(expected_input_count..); + if let Some(excess @ [begin @ end] | excess @ [begin, .., end]) = excess { + tcx.sess.emit_err(ProcMacroDiffArguments { + span: begin.span.to(end.span), + count: excess.len(), + kind, + expected_signature, + }); + self.abort.set(true); + } + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { @@ -2225,12 +2356,15 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) } fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - let check_attr_visitor = &mut CheckAttrVisitor { tcx }; + let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) }; tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor); if module_def_id.is_top_level_module() { check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); } + if check_attr_visitor.abort.get() { + tcx.sess.abort_if_errors() + } } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9c6519ea4bb24..9e05ad22e6241 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -12,6 +12,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{Span, Symbol, DUMMY_SP}; +use crate::check_attr::ProcMacroKind; use crate::lang_items::Duplicate; #[derive(Diagnostic)] @@ -1515,3 +1516,52 @@ pub struct ChangeFieldsToBeOfUnitType { #[suggestion_part(code = "()")] pub spans: Vec, } + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_typeerror)] +#[note] +pub(crate) struct ProcMacroTypeError<'tcx> { + #[primary_span] + #[label] + pub span: Span, + pub found: Ty<'tcx>, + pub kind: ProcMacroKind, + pub expected_signature: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_diff_arg_count)] +pub(crate) struct ProcMacroDiffArguments { + #[primary_span] + #[label] + pub span: Span, + pub count: usize, + pub kind: ProcMacroKind, + pub expected_signature: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_missing_args)] +pub(crate) struct ProcMacroMissingArguments { + #[primary_span] + #[label] + pub span: Span, + pub expected_input_count: usize, + pub kind: ProcMacroKind, + pub expected_signature: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_invalid_abi)] +pub(crate) struct ProcMacroInvalidAbi { + #[primary_span] + pub span: Span, + pub abi: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_unsafe)] +pub(crate) struct ProcMacroUnsafe { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7597b8d126a9c..2bccd46b08fcf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -288,6 +288,7 @@ symbols! { Target, ToOwned, ToString, + TokenStream, Try, TryCaptureGeneric, TryCapturePrintable, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 40b9bedc84fd3..d59fa71406c31 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,5 +1,6 @@ use std::mem; +use super::{Certainty, InferCtxtEvalExt}; use rustc_infer::{ infer::InferCtxt, traits::{ @@ -8,8 +9,6 @@ use rustc_infer::{ }, }; -use super::{search_graph, Certainty, EvalCtxt}; - /// A trait engine using the new trait solver. /// /// This is mostly identical to how `evaluate_all` works inside of the @@ -66,9 +65,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let search_graph = &mut search_graph::SearchGraph::new(infcx.tcx); - let mut ecx = EvalCtxt::new_outside_solver(infcx, search_graph); - let (changed, certainty) = match ecx.evaluate_goal(goal) { + let (changed, certainty) = match infcx.evaluate_root_goal(goal) { Ok(result) => result, Err(NoSolution) => { errors.push(FulfillmentError { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index da2a1a19957e1..70f094014453e 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -152,6 +152,36 @@ impl<'tcx> TyCtxtExt<'tcx> for TyCtxt<'tcx> { } } +pub trait InferCtxtEvalExt<'tcx> { + /// Evaluates a goal from **outside** of the trait solver. + /// + /// Using this while inside of the solver is wrong as it uses a new + /// search graph which would break cycle detection. + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution>; +} + +impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution> { + let mut search_graph = search_graph::SearchGraph::new(self.tcx); + + let result = EvalCtxt { + search_graph: &mut search_graph, + infcx: self, + var_values: CanonicalVarValues::dummy(), + } + .evaluate_goal(goal); + + assert!(search_graph.is_empty()); + result + } +} + struct EvalCtxt<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, var_values: CanonicalVarValues<'tcx>, @@ -164,18 +194,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.infcx.tcx } - /// Creates a new evaluation context outside of the trait solver. - /// - /// With this solver making a canonical response doesn't make much sense. - /// The `search_graph` for this solver has to be completely empty. - fn new_outside_solver( - infcx: &'a InferCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph<'tcx>, - ) -> EvalCtxt<'a, 'tcx> { - assert!(search_graph.is_empty()); - EvalCtxt { infcx, var_values: CanonicalVarValues::dummy(), search_graph } - } - #[instrument(level = "debug", skip(tcx, search_graph), ret)] fn evaluate_canonical_goal( tcx: TyCtxt<'tcx>, diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 7757068a4f2b9..f74e563f1b9c0 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -298,3 +298,7 @@ impl const From for OnceCell { OnceCell { inner: UnsafeCell::new(Some(value)) } } } + +// Just like for `Cell` this isn't needed, but results in nicer error messages. +#[unstable(feature = "once_cell", issue = "74465")] +impl !Sync for OnceCell {} diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1326fc9ab096f..74055602ec2e6 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -469,6 +469,62 @@ pub macro Copy($item:item) { #[cfg_attr(not(test), rustc_diagnostic_item = "Sync")] #[lang = "sync"] #[rustc_on_unimplemented( + on( + _Self = "std::cell::OnceCell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead" + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead", + ), + on( + _Self = "std::cell::Cell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`", + ), + on( + _Self = "std::cell::RefCell", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", + ), message = "`{Self}` cannot be shared between threads safely", label = "`{Self}` cannot be shared between threads safely" )] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 7b1cb5488bcac..16eb726f6f614 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -731,7 +731,7 @@ impl *const T { /// This computes the same value that [`offset_from`](#method.offset_from) /// would compute, but with the added precondition that the offset is /// guaranteed to be non-negative. This method is equivalent to - /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`, + /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`, /// but it provides slightly more information to the optimizer, which can /// sometimes allow it to optimize slightly better with some backends. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ed1e3bd481227..0a2f63e3ec6a5 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -904,7 +904,7 @@ impl *mut T { /// This computes the same value that [`offset_from`](#method.offset_from) /// would compute, but with the added precondition that the offset is /// guaranteed to be non-negative. This method is equivalent to - /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`, + /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`, /// but it provides slightly more information to the optimizer, which can /// sometimes allow it to optimize slightly better with some backends. /// diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index f0e4f5d8a8013..8bff40c279aaa 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -74,6 +74,7 @@ pub fn is_available() -> bool { /// /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` /// and `#[proc_macro_derive]` definitions. +#[rustc_diagnostic_item = "TokenStream"] #[stable(feature = "proc_macro_lib", since = "1.15.0")] #[derive(Clone)] pub struct TokenStream(Option); diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index be69f819c6428..db42212821018 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -6,6 +6,8 @@ //! directory in each respective module. use std::env; +use std::fs::File; +use std::io::{BufRead, BufReader}; use bootstrap::{t, Build, Config, Subcommand, VERSION}; @@ -16,12 +18,17 @@ fn main() { let mut build_lock; let _build_lock_guard; if cfg!(any(unix, windows)) { - build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(config.out.join("lock")))); + let path = config.out.join("lock"); + build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path))); _build_lock_guard = match build_lock.try_write() { Ok(lock) => lock, err => { - println!("warning: build directory locked, waiting for lock"); drop(err); + if let Some(pid) = get_lock_owner(&path) { + println!("warning: build directory locked by process {pid}, waiting for lock"); + } else { + println!("warning: build directory locked, waiting for lock"); + } t!(build_lock.write()) } }; @@ -98,3 +105,27 @@ fn check_version(config: &Config) -> Option { Some(msg) } + +/// Get the PID of the process which took the write lock by +/// parsing `/proc/locks`. +#[cfg(target_os = "linux")] +fn get_lock_owner(f: &std::path::Path) -> Option { + use std::os::unix::fs::MetadataExt; + let lock_inode = std::fs::metadata(f).ok()?.ino(); + let lockfile = File::open("/proc/locks").ok()?; + BufReader::new(lockfile).lines().find_map(|line| { + // pid--vvvvvv vvvvvvv--- inode + // 21: FLOCK ADVISORY WRITE 359238 08:02:3719774 0 EOF + let line = line.ok()?; + let parts = line.split_whitespace().collect::>(); + let (pid, inode) = (parts[4].parse::().ok()?, &parts[5]); + let inode = inode.rsplit_once(':')?.1.parse::().ok()?; + if inode == lock_inode { Some(pid) } else { None } + }) +} + +#[cfg(not(target_os = "linux"))] +fn get_lock_owner(f: &std::path::Path) -> Option { + // FIXME: Implement on other OS's + None +} diff --git a/tests/mir-opt/building/custom/operators.f.built.after.mir b/tests/mir-opt/building/custom/operators.f.built.after.mir new file mode 100644 index 0000000000000..a0c5f1b40dbb7 --- /dev/null +++ b/tests/mir-opt/building/custom/operators.f.built.after.mir @@ -0,0 +1,26 @@ +// MIR for `f` after built + +fn f(_1: i32, _2: bool) -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/operators.rs:+0:30: +0:33 + + bb0: { + _1 = Neg(_1); // scope 0 at $DIR/operators.rs:+2:9: +2:15 + _2 = Not(_2); // scope 0 at $DIR/operators.rs:+3:9: +3:15 + _1 = Add(_1, _1); // scope 0 at $DIR/operators.rs:+4:9: +4:18 + _1 = Sub(_1, _1); // scope 0 at $DIR/operators.rs:+5:9: +5:18 + _1 = Mul(_1, _1); // scope 0 at $DIR/operators.rs:+6:9: +6:18 + _1 = Div(_1, _1); // scope 0 at $DIR/operators.rs:+7:9: +7:18 + _1 = Rem(_1, _1); // scope 0 at $DIR/operators.rs:+8:9: +8:18 + _1 = BitXor(_1, _1); // scope 0 at $DIR/operators.rs:+9:9: +9:18 + _1 = BitAnd(_1, _1); // scope 0 at $DIR/operators.rs:+10:9: +10:18 + _1 = Shl(_1, _1); // scope 0 at $DIR/operators.rs:+11:9: +11:19 + _1 = Shr(_1, _1); // scope 0 at $DIR/operators.rs:+12:9: +12:19 + _2 = Eq(_1, _1); // scope 0 at $DIR/operators.rs:+13:9: +13:19 + _2 = Lt(_1, _1); // scope 0 at $DIR/operators.rs:+14:9: +14:18 + _2 = Le(_1, _1); // scope 0 at $DIR/operators.rs:+15:9: +15:19 + _2 = Ge(_1, _1); // scope 0 at $DIR/operators.rs:+16:9: +16:19 + _2 = Gt(_1, _1); // scope 0 at $DIR/operators.rs:+17:9: +17:18 + _0 = _1; // scope 0 at $DIR/operators.rs:+18:9: +18:16 + return; // scope 0 at $DIR/operators.rs:+19:9: +19:17 + } +} diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs new file mode 100644 index 0000000000000..51f80c66392a1 --- /dev/null +++ b/tests/mir-opt/building/custom/operators.rs @@ -0,0 +1,28 @@ +// compile-flags: --crate-type=lib +#![feature(custom_mir, core_intrinsics, inline_const)] +use std::intrinsics::mir::*; + +// EMIT_MIR operators.f.built.after.mir +#[custom_mir(dialect = "built")] +pub fn f(a: i32, b: bool) -> i32 { + mir!({ + a = -a; + b = !b; + a = a + a; + a = a - a; + a = a * a; + a = a / a; + a = a % a; + a = a ^ a; + a = a & a; + a = a << a; + a = a >> a; + b = a == a; + b = a < a; + b = a <= a; + b = a >= a; + b = a > a; + RET = a; + Return() + }) +} diff --git a/tests/ui/async-await/issue-68112.drop_tracking.stderr b/tests/ui/async-await/issue-68112.drop_tracking.stderr index f2802698fd5b6..bd648de30672d 100644 --- a/tests/ui/async-await/issue-68112.drop_tracking.stderr +++ b/tests/ui/async-await/issue-68112.drop_tracking.stderr @@ -5,6 +5,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:34:17 | @@ -23,6 +24,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:43:17 | @@ -43,6 +45,7 @@ LL | require_send(send_fut); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this `async fn` body --> $DIR/issue-68112.rs:50:31 diff --git a/tests/ui/async-await/issue-68112.no_drop_tracking.stderr b/tests/ui/async-await/issue-68112.no_drop_tracking.stderr index 38eb85b302fd5..35b7341f63a4d 100644 --- a/tests/ui/async-await/issue-68112.no_drop_tracking.stderr +++ b/tests/ui/async-await/issue-68112.no_drop_tracking.stderr @@ -5,6 +5,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:34:17 | @@ -23,6 +24,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:43:17 | @@ -43,6 +45,7 @@ LL | require_send(send_fut); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this `async fn` body --> $DIR/issue-68112.rs:50:31 diff --git a/tests/ui/generator/issue-68112.rs b/tests/ui/generator/issue-68112.rs index 21026f45cb823..9def544e3d25c 100644 --- a/tests/ui/generator/issue-68112.rs +++ b/tests/ui/generator/issue-68112.rs @@ -40,6 +40,7 @@ fn test1() { require_send(send_gen); //~^ ERROR generator cannot be sent between threads //~| NOTE not `Send` + //~| NOTE use `std::sync::RwLock` instead } pub fn make_gen2(t: T) -> impl Generator { @@ -66,6 +67,7 @@ fn test2() { //~| NOTE required for //~| NOTE required by a bound introduced by this call //~| NOTE captures the following types + //~| NOTE use `std::sync::RwLock` instead } fn main() {} diff --git a/tests/ui/generator/issue-68112.stderr b/tests/ui/generator/issue-68112.stderr index eb99d42c92068..b42bc93d01f66 100644 --- a/tests/ui/generator/issue-68112.stderr +++ b/tests/ui/generator/issue-68112.stderr @@ -5,6 +5,7 @@ LL | require_send(send_gen); | ^^^^^^^^ generator is not `Send` | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: generator is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:36:9 | @@ -23,7 +24,7 @@ LL | fn require_send(_: impl Send) {} | ^^^^ required by this bound in `require_send` error[E0277]: `RefCell` cannot be shared between threads safely - --> $DIR/issue-68112.rs:63:18 + --> $DIR/issue-68112.rs:64:18 | LL | require_send(send_gen); | ------------ ^^^^^^^^ `RefCell` cannot be shared between threads safely @@ -31,25 +32,26 @@ LL | require_send(send_gen); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this generator - --> $DIR/issue-68112.rs:48:5 + --> $DIR/issue-68112.rs:49:5 | LL | || { | ^^ note: required because it appears within the type `impl Generator>>` - --> $DIR/issue-68112.rs:45:30 + --> $DIR/issue-68112.rs:46:30 | LL | pub fn make_gen2(t: T) -> impl Generator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `impl Generator>>` - --> $DIR/issue-68112.rs:53:34 + --> $DIR/issue-68112.rs:54:34 | LL | fn make_non_send_generator2() -> impl Generator>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: required because it captures the following types: `impl Generator>>`, `()` note: required because it's used within this generator - --> $DIR/issue-68112.rs:59:20 + --> $DIR/issue-68112.rs:60:20 | LL | let send_gen = || { | ^^ diff --git a/tests/ui/generator/not-send-sync.stderr b/tests/ui/generator/not-send-sync.stderr index a821c57b923a0..1711df729b8c0 100644 --- a/tests/ui/generator/not-send-sync.stderr +++ b/tests/ui/generator/not-send-sync.stderr @@ -12,6 +12,7 @@ LL | | }); | |_____^ `Cell` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead = note: required for `&Cell` to implement `Send` note: required because it's used within this generator --> $DIR/not-send-sync.rs:16:17 @@ -36,6 +37,7 @@ LL | | }); | |_____^ generator is not `Sync` | = help: within `[generator@$DIR/not-send-sync.rs:9:17: 9:19]`, the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead note: generator is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:12:9 | diff --git a/tests/ui/generator/print/generator-print-verbose-1.stderr b/tests/ui/generator/print/generator-print-verbose-1.stderr index ebf35be581c60..45d018b8ebad5 100644 --- a/tests/ui/generator/print/generator-print-verbose-1.stderr +++ b/tests/ui/generator/print/generator-print-verbose-1.stderr @@ -5,6 +5,7 @@ LL | require_send(send_gen); | ^^^^^^^^ generator is not `Send` | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: generator is not `Send` as this value is used across a yield --> $DIR/generator-print-verbose-1.rs:35:9 | @@ -29,6 +30,7 @@ LL | require_send(send_gen); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` note: required because it's used within this generator --> $DIR/generator-print-verbose-1.rs:42:5 diff --git a/tests/ui/generator/print/generator-print-verbose-2.stderr b/tests/ui/generator/print/generator-print-verbose-2.stderr index 909e49c38b8d1..59112ce0a79e6 100644 --- a/tests/ui/generator/print/generator-print-verbose-2.stderr +++ b/tests/ui/generator/print/generator-print-verbose-2.stderr @@ -12,6 +12,7 @@ LL | | }); | |_____^ `Cell` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead = note: required for `&'_#4r Cell` to implement `Send` note: required because it's used within this generator --> $DIR/generator-print-verbose-2.rs:19:17 @@ -36,6 +37,7 @@ LL | | }); | |_____^ generator is not `Sync` | = help: within `[main::{closure#0} upvar_tys=() {Cell, ()}]`, the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead note: generator is not `Sync` as this value is used across a yield --> $DIR/generator-print-verbose-2.rs:15:9 | diff --git a/tests/ui/issues/issue-7364.stderr b/tests/ui/issues/issue-7364.stderr index 5dc8c2b607e61..aee73380f15e7 100644 --- a/tests/ui/issues/issue-7364.stderr +++ b/tests/ui/issues/issue-7364.stderr @@ -5,6 +5,7 @@ LL | static boxed: Box> = Box::new(RefCell::new(0)); | ^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Unique>` to implement `Sync` = note: required because it appears within the type `Box>` = note: shared static variables must have a type that implements `Sync` diff --git a/tests/ui/parser/anon-enums.rs b/tests/ui/parser/anon-enums.rs new file mode 100644 index 0000000000000..56b8a3d43bedf --- /dev/null +++ b/tests/ui/parser/anon-enums.rs @@ -0,0 +1,17 @@ +fn foo(x: bool | i32) -> i32 | f64 { +//~^ ERROR anonymous enums are not supported +//~| ERROR anonymous enums are not supported + match x { + x: i32 => x, //~ ERROR expected + true => 42., + false => 0.333, + } +} + +fn main() { + match foo(true) { + 42: i32 => (), //~ ERROR expected + _: f64 => (), //~ ERROR expected + x: i32 => (), //~ ERROR expected + } +} diff --git a/tests/ui/parser/anon-enums.stderr b/tests/ui/parser/anon-enums.stderr new file mode 100644 index 0000000000000..8415822566091 --- /dev/null +++ b/tests/ui/parser/anon-enums.stderr @@ -0,0 +1,68 @@ +error: anonymous enums are not supported + --> $DIR/anon-enums.rs:1:16 + | +LL | fn foo(x: bool | i32) -> i32 | f64 { + | ---- ^ --- + | + = help: create a named `enum` and use it here instead: + enum Name { + Variant1(bool), + Variant2(i32), + } + +error: anonymous enums are not supported + --> $DIR/anon-enums.rs:1:30 + | +LL | fn foo(x: bool | i32) -> i32 | f64 { + | --- ^ --- + | + = help: create a named `enum` and use it here instead: + enum Name { + Variant1(i32), + Variant2(f64), + } + +error: expected one of `@` or `|`, found `:` + --> $DIR/anon-enums.rs:5:10 + | +LL | x: i32 => x, + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `@` or `|` + | +help: maybe write a path separator here + | +LL | x::i32 => x, + | ~~ + +error: expected one of `...`, `..=`, `..`, or `|`, found `:` + --> $DIR/anon-enums.rs:13:11 + | +LL | 42: i32 => (), + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `...`, `..=`, `..`, or `|` + +error: expected `|`, found `:` + --> $DIR/anon-enums.rs:14:10 + | +LL | _: f64 => (), + | ^ --- specifying the type of a pattern isn't supported + | | + | expected `|` + +error: expected one of `@` or `|`, found `:` + --> $DIR/anon-enums.rs:15:10 + | +LL | x: i32 => (), + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `@` or `|` + | +help: maybe write a path separator here + | +LL | x::i32 => (), + | ~~ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/parser/fake-anon-enums-in-macros.rs b/tests/ui/parser/fake-anon-enums-in-macros.rs new file mode 100644 index 0000000000000..38fe8dee23829 --- /dev/null +++ b/tests/ui/parser/fake-anon-enums-in-macros.rs @@ -0,0 +1,20 @@ +// build-pass +macro_rules! check_ty { + ($Z:ty) => { compile_error!("triggered"); }; + ($X:ty | $Y:ty) => { $X }; +} + +macro_rules! check { + ($Z:ty) => { compile_error!("triggered"); }; + ($X:ty | $Y:ty) => { }; +} + +check! { i32 | u8 } + +fn foo(x: check_ty! { i32 | u8 }) -> check_ty! { i32 | u8 } { + x +} +fn main() { + let x: check_ty! { i32 | u8 } = 42; + let _: check_ty! { i32 | u8 } = foo(x); +} diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs index 0b7b67496d6f3..e1ea38f2795df 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs @@ -68,7 +68,6 @@ fn main() { Foo:Bar::Baz => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here - //~| ERROR: failed to resolve: `Bar` is a variant, not a module } match myfoo { Foo::Bar => {} diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr index 2050a16beb349..63b072ac4cdc6 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr @@ -2,89 +2,118 @@ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:17:12 | LL | Foo:Bar => {} - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | Foo::Bar => {} + | ~~ error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:23:17 | LL | qux::Foo:Bar => {} - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of 8 possible tokens - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | qux::Foo::Bar => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:29:12 | LL | qux:Foo::Baz => {} - | ^ + | ^-------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | qux::Foo::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:35:12 | LL | qux: Foo::Baz if true => {} - | ^ + | ^ -------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | qux::Foo::Baz if true => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:40:15 | LL | if let Foo:Bar = f() { - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | if let Foo::Bar = f() { + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:48:16 | LL | ref qux: Foo::Baz => {} - | ^ + | ^ -------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | ref qux::Foo::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:57:16 | LL | mut qux: Foo::Baz => {} - | ^ + | ^ -------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | mut qux::Foo::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:68:12 | LL | Foo:Bar::Baz => {} - | ^ + | ^-------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | Foo::Bar::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:75:12 + --> $DIR/issue-87086-colon-path-sep.rs:74:12 | LL | Foo:Bar => {} - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` - -error[E0433]: failed to resolve: `Bar` is a variant, not a module - --> $DIR/issue-87086-colon-path-sep.rs:68:13 | -LL | Foo:Bar::Baz => {} - | ^^^ `Bar` is a variant, not a module +help: maybe write a path separator here + | +LL | Foo::Bar => {} + | ~~ -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/proc-macro/allowed-signatures.rs b/tests/ui/proc-macro/allowed-signatures.rs new file mode 100644 index 0000000000000..8685087611248 --- /dev/null +++ b/tests/ui/proc-macro/allowed-signatures.rs @@ -0,0 +1,26 @@ +// check-pass +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![allow(private_in_public)] +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn foo(t: T) -> TokenStream { + TokenStream::new() +} + +trait Project { + type Assoc; +} + +impl Project for () { + type Assoc = TokenStream; +} + +#[proc_macro] +pub fn uwu(_input: <() as Project>::Assoc) -> <() as Project>::Assoc { + TokenStream::new() +} diff --git a/tests/ui/proc-macro/proc-macro-abi.rs b/tests/ui/proc-macro/proc-macro-abi.rs new file mode 100644 index 0000000000000..873660a5b3ab9 --- /dev/null +++ b/tests/ui/proc-macro/proc-macro-abi.rs @@ -0,0 +1,31 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![allow(warnings)] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub extern "C" fn abi(a: TokenStream) -> TokenStream { + //~^ ERROR proc macro functions may not be `extern "C"` + a +} + +#[proc_macro] +pub extern "system" fn abi2(a: TokenStream) -> TokenStream { + //~^ ERROR proc macro functions may not be `extern "system"` + a +} + +#[proc_macro] +pub extern fn abi3(a: TokenStream) -> TokenStream { + //~^ ERROR proc macro functions may not be `extern "C"` + a +} + +#[proc_macro] +pub extern "Rust" fn abi4(a: TokenStream) -> TokenStream { + a +} diff --git a/tests/ui/proc-macro/proc-macro-abi.stderr b/tests/ui/proc-macro/proc-macro-abi.stderr new file mode 100644 index 0000000000000..9a781be0996dd --- /dev/null +++ b/tests/ui/proc-macro/proc-macro-abi.stderr @@ -0,0 +1,20 @@ +error: proc macro functions may not be `extern "C"` + --> $DIR/proc-macro-abi.rs:11:1 + | +LL | pub extern "C" fn abi(a: TokenStream) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: proc macro functions may not be `extern "system"` + --> $DIR/proc-macro-abi.rs:17:1 + | +LL | pub extern "system" fn abi2(a: TokenStream) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: proc macro functions may not be `extern "C"` + --> $DIR/proc-macro-abi.rs:23:1 + | +LL | pub extern fn abi3(a: TokenStream) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.rs b/tests/ui/proc-macro/signature-proc-macro-attribute.rs new file mode 100644 index 0000000000000..51abc8e7d3edb --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-attribute.rs @@ -0,0 +1,32 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn bad_input(input: String) -> TokenStream { + //~^ ERROR mismatched attribute proc macro signature + ::proc_macro::TokenStream::new() +} + +#[proc_macro_attribute] +pub fn bad_output(input: TokenStream) -> String { + //~^ ERROR mismatched attribute proc macro signature + //~| ERROR mismatched attribute proc macro signature + String::from("blah") +} + +#[proc_macro_attribute] +pub fn bad_everything(input: String) -> String { + //~^ ERROR mismatched attribute proc macro signature + //~| ERROR mismatched attribute proc macro signature + input +} + +#[proc_macro_attribute] +pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + //~^ ERROR mismatched attribute proc macro signature +} diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr new file mode 100644 index 0000000000000..abf7a6f3ce922 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr @@ -0,0 +1,42 @@ +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:10:1 + | +LL | pub fn bad_input(input: String) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:16:42 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:16:1 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:23:41 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:23:1 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:30:49 + | +LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + | ^^^^^^^^^ found unexpected argument + +error: aborting due to 6 previous errors + diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.rs b/tests/ui/proc-macro/signature-proc-macro-derive.rs new file mode 100644 index 0000000000000..f2fd824b675b6 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-derive.rs @@ -0,0 +1,31 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(Blah)] +pub fn bad_input(input: String) -> TokenStream { + //~^ ERROR mismatched derive proc macro signature + TokenStream::new() +} + +#[proc_macro_derive(Bleh)] +pub fn bad_output(input: TokenStream) -> String { + //~^ ERROR mismatched derive proc macro signature + String::from("blah") +} + +#[proc_macro_derive(Bluh)] +pub fn bad_everything(input: String) -> String { + //~^ ERROR mismatched derive proc macro signature + //~| ERROR mismatched derive proc macro signature + input +} + +#[proc_macro_derive(Blih)] +pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + //~^ ERROR mismatched derive proc macro signature +} diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.stderr b/tests/ui/proc-macro/signature-proc-macro-derive.stderr new file mode 100644 index 0000000000000..a358ae277037f --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-derive.stderr @@ -0,0 +1,40 @@ +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:10:25 + | +LL | pub fn bad_input(input: String) -> TokenStream { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:16:42 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:22:41 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:22:30 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:29:33 + | +LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments + +error: aborting due to 5 previous errors + diff --git a/tests/ui/proc-macro/signature-proc-macro.rs b/tests/ui/proc-macro/signature-proc-macro.rs new file mode 100644 index 0000000000000..54770aacd1a98 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro.rs @@ -0,0 +1,31 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn bad_input(input: String) -> TokenStream { + //~^ ERROR mismatched function-like proc macro signature + ::proc_macro::TokenStream::new() +} + +#[proc_macro] +pub fn bad_output(input: TokenStream) -> String { + //~^ ERROR mismatched function-like proc macro signature + String::from("blah") +} + +#[proc_macro] +pub fn bad_everything(input: String) -> String { + //~^ ERROR mismatched function-like proc macro signature + //~| ERROR mismatched function-like proc macro signature + input +} + +#[proc_macro] +pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + //~^ ERROR mismatched function-like proc macro signature +} diff --git a/tests/ui/proc-macro/signature-proc-macro.stderr b/tests/ui/proc-macro/signature-proc-macro.stderr new file mode 100644 index 0000000000000..4b14a54e67503 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro.stderr @@ -0,0 +1,40 @@ +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:10:25 + | +LL | pub fn bad_input(input: String) -> TokenStream { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:16:42 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:22:41 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:22:30 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:29:33 + | +LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments + +error: aborting due to 5 previous errors + diff --git a/tests/ui/proc-macro/signature.rs b/tests/ui/proc-macro/signature.rs index 2302238253e82..11187aa31bd80 100644 --- a/tests/ui/proc-macro/signature.rs +++ b/tests/ui/proc-macro/signature.rs @@ -8,6 +8,10 @@ extern crate proc_macro; #[proc_macro_derive(A)] pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { - //~^ ERROR: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn + //~^ ERROR: mismatched derive proc macro signature + //~| mismatched derive proc macro signature + //~| mismatched derive proc macro signature + //~| proc macro functions may not be `extern + //~| proc macro functions may not be `unsafe loop {} } diff --git a/tests/ui/proc-macro/signature.stderr b/tests/ui/proc-macro/signature.stderr index 79f2001da0055..3dbe3f22a0df8 100644 --- a/tests/ui/proc-macro/signature.stderr +++ b/tests/ui/proc-macro/signature.stderr @@ -1,20 +1,36 @@ -error[E0277]: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn(i32, u32) -> u32 {foo}` +error: proc macro functions may not be `extern "C"` --> $DIR/signature.rs:10:1 | -LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { -LL | | -LL | | loop {} -LL | | } - | | ^ - | | | - | |_call the function in a closure: `|| unsafe { /* code */ }` - | required by a bound introduced by this call +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: proc macro functions may not be `unsafe` + --> $DIR/signature.rs:10:1 + | +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mismatched derive proc macro signature + --> $DIR/signature.rs:10:49 + | +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^ found u32, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature.rs:10:33 + | +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^ found i32, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature.rs:10:38 | - = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}` - = note: unsafe function cannot be called generically without an unsafe block -note: required by a bound in `ProcMacro::custom_derive` - --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^^^^ found unexpected argument -error: aborting due to previous error +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/stdlib-unit-tests/not-sync.stderr b/tests/ui/stdlib-unit-tests/not-sync.stderr index 1ee358ba8368e..4e34e10e37789 100644 --- a/tests/ui/stdlib-unit-tests/not-sync.stderr +++ b/tests/ui/stdlib-unit-tests/not-sync.stderr @@ -5,6 +5,7 @@ LL | test::>(); | ^^^^^^^^^ `Cell` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead note: required by a bound in `test` --> $DIR/not-sync.rs:5:12 | @@ -18,6 +19,7 @@ LL | test::>(); | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `RefCell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: required by a bound in `test` --> $DIR/not-sync.rs:5:12 | diff --git a/tests/ui/mutexguard-sync.rs b/tests/ui/sync/mutexguard-sync.rs similarity index 100% rename from tests/ui/mutexguard-sync.rs rename to tests/ui/sync/mutexguard-sync.rs diff --git a/tests/ui/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr similarity index 83% rename from tests/ui/mutexguard-sync.stderr rename to tests/ui/sync/mutexguard-sync.stderr index 3fbb2ddf183d3..4dc5571196c14 100644 --- a/tests/ui/mutexguard-sync.stderr +++ b/tests/ui/sync/mutexguard-sync.stderr @@ -7,6 +7,7 @@ LL | test_sync(guard); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead = note: required for `MutexGuard<'_, Cell>` to implement `Sync` note: required by a bound in `test_sync` --> $DIR/mutexguard-sync.rs:5:17 diff --git a/tests/ui/sync/suggest-cell.rs b/tests/ui/sync/suggest-cell.rs new file mode 100644 index 0000000000000..3284eae7be181 --- /dev/null +++ b/tests/ui/sync/suggest-cell.rs @@ -0,0 +1,31 @@ +fn require_sync() {} +//~^ NOTE required by this bound in `require_sync` +//~| NOTE required by this bound in `require_sync` +//~| NOTE required by this bound in `require_sync` +//~| NOTE required by this bound in `require_sync` +//~| NOTE required by a bound in `require_sync` +//~| NOTE required by a bound in `require_sync` +//~| NOTE required by a bound in `require_sync` +//~| NOTE required by a bound in `require_sync` + +fn main() { + require_sync::>(); + //~^ ERROR `Cell<()>` cannot be shared between threads safely + //~| NOTE `Cell<()>` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` + + require_sync::>(); + //~^ ERROR `Cell` cannot be shared between threads safely + //~| NOTE `Cell` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead + + require_sync::>(); + //~^ ERROR `Cell` cannot be shared between threads safely + //~| NOTE `Cell` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead + + require_sync::>(); + //~^ ERROR `Cell` cannot be shared between threads safely + //~| NOTE `Cell` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead +} diff --git a/tests/ui/sync/suggest-cell.stderr b/tests/ui/sync/suggest-cell.stderr new file mode 100644 index 0000000000000..c232c1ccd53dd --- /dev/null +++ b/tests/ui/sync/suggest-cell.stderr @@ -0,0 +1,59 @@ +error[E0277]: `Cell<()>` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:12:20 + | +LL | require_sync::>(); + | ^^^^^^^^^^^^^^^^^^^ `Cell<()>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell<()>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync() {} + | ^^^^ required by this bound in `require_sync` + +error[E0277]: `Cell` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:17:20 + | +LL | require_sync::>(); + | ^^^^^^^^^^^^^^^^^^^ `Cell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync() {} + | ^^^^ required by this bound in `require_sync` + +error[E0277]: `Cell` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:22:20 + | +LL | require_sync::>(); + | ^^^^^^^^^^^^^^^^^^^^ `Cell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync() {} + | ^^^^ required by this bound in `require_sync` + +error[E0277]: `Cell` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:27:20 + | +LL | require_sync::>(); + | ^^^^^^^^^^^^^^^^^^^^^ `Cell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync() {} + | ^^^^ required by this bound in `require_sync` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/sync/suggest-once-cell.rs b/tests/ui/sync/suggest-once-cell.rs new file mode 100644 index 0000000000000..82fca45b1a47f --- /dev/null +++ b/tests/ui/sync/suggest-once-cell.rs @@ -0,0 +1,12 @@ +#![feature(once_cell)] + +fn require_sync() {} +//~^ NOTE required by this bound in `require_sync` +//~| NOTE required by a bound in `require_sync` + +fn main() { + require_sync::>(); + //~^ ERROR `OnceCell<()>` cannot be shared between threads safely + //~| NOTE `OnceCell<()>` cannot be shared between threads safely + //~| NOTE use `std::sync::OnceLock` instead +} diff --git a/tests/ui/sync/suggest-once-cell.stderr b/tests/ui/sync/suggest-once-cell.stderr new file mode 100644 index 0000000000000..fadf05374d8ca --- /dev/null +++ b/tests/ui/sync/suggest-once-cell.stderr @@ -0,0 +1,17 @@ +error[E0277]: `OnceCell<()>` cannot be shared between threads safely + --> $DIR/suggest-once-cell.rs:8:20 + | +LL | require_sync::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ `OnceCell<()>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `OnceCell<()>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-once-cell.rs:3:20 + | +LL | fn require_sync() {} + | ^^^^ required by this bound in `require_sync` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/sync/suggest-ref-cell.rs b/tests/ui/sync/suggest-ref-cell.rs new file mode 100644 index 0000000000000..6b972ae09622e --- /dev/null +++ b/tests/ui/sync/suggest-ref-cell.rs @@ -0,0 +1,12 @@ +#![feature(once_cell)] + +fn require_sync() {} +//~^ NOTE required by this bound in `require_sync` +//~| NOTE required by a bound in `require_sync` + +fn main() { + require_sync::>(); + //~^ ERROR `RefCell<()>` cannot be shared between threads safely + //~| NOTE `RefCell<()>` cannot be shared between threads safely + //~| NOTE use `std::sync::RwLock` instead +} diff --git a/tests/ui/sync/suggest-ref-cell.stderr b/tests/ui/sync/suggest-ref-cell.stderr new file mode 100644 index 0000000000000..9e8b8fcb42ed0 --- /dev/null +++ b/tests/ui/sync/suggest-ref-cell.stderr @@ -0,0 +1,17 @@ +error[E0277]: `RefCell<()>` cannot be shared between threads safely + --> $DIR/suggest-ref-cell.rs:8:20 + | +LL | require_sync::>(); + | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<()>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell<()>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-ref-cell.rs:3:20 + | +LL | fn require_sync() {} + | ^^^^ required by this bound in `require_sync` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.rs b/tests/ui/type/type-check/coerce-result-return-value-2.rs new file mode 100644 index 0000000000000..23bafa6c5c94c --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value-2.rs @@ -0,0 +1,24 @@ +struct A; +struct B; +impl From for B { + fn from(_: A) -> Self { B } +} +fn foo4(x: Result<(), A>) -> Result<(), B> { + match true { + true => x, //~ ERROR mismatched types + false => x, + } +} +fn foo5(x: Result<(), A>) -> Result<(), B> { + match true { + true => return x, //~ ERROR mismatched types + false => return x, + } +} +fn main() { + let _ = foo4(Ok(())); + let _ = foo5(Ok(())); + let _: Result<(), B> = { //~ ERROR mismatched types + Err(A); + }; +} diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.stderr b/tests/ui/type/type-check/coerce-result-return-value-2.stderr new file mode 100644 index 0000000000000..5992162341e6e --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value-2.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value-2.rs:8:17 + | +LL | fn foo4(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | match true { +LL | true => x, + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | true => Ok(x?), + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value-2.rs:14:24 + | +LL | fn foo5(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | match true { +LL | true => return x, + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | true => return Ok(x?), + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value-2.rs:21:28 + | +LL | let _: Result<(), B> = { + | ____________________________^ +LL | | Err(A); +LL | | }; + | |_____^ expected enum `Result`, found `()` + | + = note: expected enum `Result<(), B>` + found unit type `()` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type/type-check/coerce-result-return-value.fixed b/tests/ui/type/type-check/coerce-result-return-value.fixed new file mode 100644 index 0000000000000..8a05407070dad --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.fixed @@ -0,0 +1,24 @@ +// run-rustfix +struct A; +struct B; +impl From for B { + fn from(_: A) -> Self { B } +} +fn foo1(x: Result<(), A>) -> Result<(), B> { + Ok(x?) //~ ERROR mismatched types +} +fn foo2(x: Result<(), A>) -> Result<(), B> { + return Ok(x?); //~ ERROR mismatched types +} +fn foo3(x: Result<(), A>) -> Result<(), B> { + if true { + Ok(x?) //~ ERROR mismatched types + } else { + Ok(x?) //~ ERROR mismatched types + } +} +fn main() { + let _ = foo1(Ok(())); + let _ = foo2(Ok(())); + let _ = foo3(Ok(())); +} diff --git a/tests/ui/type/type-check/coerce-result-return-value.rs b/tests/ui/type/type-check/coerce-result-return-value.rs new file mode 100644 index 0000000000000..442203addb787 --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.rs @@ -0,0 +1,24 @@ +// run-rustfix +struct A; +struct B; +impl From for B { + fn from(_: A) -> Self { B } +} +fn foo1(x: Result<(), A>) -> Result<(), B> { + x //~ ERROR mismatched types +} +fn foo2(x: Result<(), A>) -> Result<(), B> { + return x; //~ ERROR mismatched types +} +fn foo3(x: Result<(), A>) -> Result<(), B> { + if true { + x //~ ERROR mismatched types + } else { + x //~ ERROR mismatched types + } +} +fn main() { + let _ = foo1(Ok(())); + let _ = foo2(Ok(())); + let _ = foo3(Ok(())); +} diff --git a/tests/ui/type/type-check/coerce-result-return-value.stderr b/tests/ui/type/type-check/coerce-result-return-value.stderr new file mode 100644 index 0000000000000..550153520782c --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.stderr @@ -0,0 +1,65 @@ +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:8:5 + | +LL | fn foo1(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | x + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | Ok(x?) + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:11:12 + | +LL | fn foo2(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | return x; + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | return Ok(x?); + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:15:9 + | +LL | fn foo3(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | if true { +LL | x + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | Ok(x?) + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:17:9 + | +LL | fn foo3(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +... +LL | x + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | Ok(x?) + | +++ ++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/bad-type-in-vec-push.rs b/tests/ui/typeck/bad-type-in-vec-push.rs new file mode 100644 index 0000000000000..a807f030cfce4 --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-push.rs @@ -0,0 +1,20 @@ +// The error message here still is pretty confusing. + +fn main() { + let mut result = vec![1]; + // The type of `result` is constrained to be `Vec<{integer}>` here. + // But the logic we use to find what expression constrains a type + // is not sophisticated enough to know this. + + let mut vector = Vec::new(); + vector.sort(); + result.push(vector); + //~^ ERROR mismatched types + // So it thinks that the type of `result` is constrained here. +} + +fn example2() { + let mut x = vec![1]; + x.push(""); + //~^ ERROR mismatched types +} diff --git a/tests/ui/typeck/bad-type-in-vec-push.stderr b/tests/ui/typeck/bad-type-in-vec-push.stderr new file mode 100644 index 0000000000000..e4c99ec8e701f --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-push.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/bad-type-in-vec-push.rs:11:17 + | +LL | vector.sort(); + | ------ here the type of `vector` is inferred to be `Vec<_>` +LL | result.push(vector); + | ---- ^^^^^^ expected integer, found struct `Vec` + | | + | arguments to this method are incorrect + | + = note: expected type `{integer}` + found struct `Vec<_>` +note: associated function defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/bad-type-in-vec-push.rs:18:12 + | +LL | x.push(""); + | ---- ^^ expected integer, found `&str` + | | + | arguments to this method are incorrect + | +note: associated function defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`.