diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 0c2242b810b69..4861b7a4430f0 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -12,8 +12,6 @@ const_eval_already_reported = const_eval_assume_false = `assume` called with `false` -const_eval_await_non_const = - cannot convert `{$ty}` into a future in {const_eval_const_context}s const_eval_bounds_check_failed = indexing out of bounds: the len is {$len} but the index is {$index} const_eval_call_nonzero_intrinsic = @@ -23,11 +21,6 @@ const_eval_closure_call = closures need an RFC before allowed to be called in {const_eval_const_context}s const_eval_closure_fndef_not_const = function defined here, but it is not `const` -const_eval_closure_non_const = - cannot call non-const closure in {const_eval_const_context}s - -const_eval_conditionally_const_call = - cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s const_eval_consider_dereferencing = consider dereferencing here @@ -62,10 +55,6 @@ const_eval_dealloc_incorrect_layout = const_eval_dealloc_kind_mismatch = deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation -const_eval_deref_coercion_non_const = - cannot perform deref coercion on `{$ty}` in {const_eval_const_context}s - .note = attempting to deref into `{$target_ty}` - .target_note = deref defined here const_eval_deref_function_pointer = accessing {$allocation} which contains a function const_eval_deref_vtable_pointer = @@ -109,9 +98,6 @@ const_eval_extern_type_field = `extern type` field does not have a known offset const_eval_fn_ptr_call = function pointers need an RFC before allowed to be called in {const_eval_const_context}s -const_eval_for_loop_into_iter_non_const = - cannot use `for` loop on `{$ty}` in {const_eval_const_context}s - const_eval_frame_note = {$times -> [0] {const_eval_frame_note_inner} *[other] [... {$times} additional calls {const_eval_frame_note_inner} ...] @@ -216,9 +202,6 @@ const_eval_long_running = .label = the const evaluator is currently interpreting this expression .help = the constant being evaluated -const_eval_match_eq_non_const = cannot match on `{$ty}` in {const_eval_const_context}s - .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es - const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} const_eval_memory_access_test = memory access failed @@ -249,11 +232,26 @@ const_eval_mutable_ref_escaping = If you really want global mutable state, try using an interior mutable `static` or a `static mut`. const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead + +const_eval_non_const_await = + cannot convert `{$ty}` into a future in {const_eval_const_context}s + +const_eval_non_const_closure = + cannot call {$non_or_conditionally}-const closure in {const_eval_const_context}s + +const_eval_non_const_deref_coercion = + cannot perform {$non_or_conditionally}-const deref coercion on `{$ty}` in {const_eval_const_context}s + .note = attempting to deref into `{$target_ty}` + .target_note = deref defined here + const_eval_non_const_fmt_macro_call = - cannot call non-const formatting macro in {const_eval_const_context}s + cannot call {$non_or_conditionally}-const formatting macro in {const_eval_const_context}s const_eval_non_const_fn_call = - cannot call non-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s + cannot call {$non_or_conditionally}-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s + +const_eval_non_const_for_loop_into_iter = + cannot use `for` loop on `{$ty}` in {const_eval_const_context}s const_eval_non_const_impl = impl defined here, but it is not `const` @@ -261,6 +259,20 @@ const_eval_non_const_impl = const_eval_non_const_intrinsic = cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s +const_eval_non_const_match_eq = cannot match on `{$ty}` in {const_eval_const_context}s + .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es + +const_eval_non_const_operator = + cannot call {$non_or_conditionally}-const operator in {const_eval_const_context}s + +const_eval_non_const_question_branch = + `?` is not allowed on `{$ty}` in {const_eval_const_context}s +const_eval_non_const_question_from_residual = + `?` is not allowed on `{$ty}` in {const_eval_const_context}s + +const_eval_non_const_try_block_from_output = + `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s + const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires @@ -281,8 +293,6 @@ const_eval_offset_from_unsigned_overflow = *[false] offset } than second: {$a_offset} < {$b_offset} -const_eval_operator_non_const = - cannot call non-const operator in {const_eval_const_context}s const_eval_overflow_arith = arithmetic overflow in `{$intrinsic}` const_eval_overflow_shift = @@ -325,11 +335,6 @@ const_eval_ptr_as_bytes_1 = const_eval_ptr_as_bytes_2 = the absolute address of a pointer is not known at compile-time, so such operations are not supported -const_eval_question_branch_non_const = - `?` is not allowed on `{$ty}` in {const_eval_const_context}s -const_eval_question_from_residual_non_const = - `?` is not allowed on `{$ty}` in {const_eval_const_context}s - const_eval_range = in the range {$lo}..={$hi} const_eval_range_lower = greater or equal to {$lo} const_eval_range_singular = equal to {$lo} @@ -379,8 +384,6 @@ const_eval_too_generic = const_eval_too_many_caller_args = calling a function with more arguments than it expected -const_eval_try_block_from_output_non_const = - `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s const_eval_unallowed_heap_allocations = diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index e895c44199b81..015e16716821a 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -708,7 +708,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if trait_is_const { // Trait calls are always conditionally-const. - self.check_op(ops::ConditionallyConstCall { callee, args: fn_args }); + self.check_op(ops::ConditionallyConstCall { + callee, + args: fn_args, + span: *fn_span, + call_source, + }); // FIXME(const_trait_impl): do a more fine-grained check whether this // particular trait can be const-stably called. } else { @@ -726,7 +731,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Even if we know the callee, ensure we can use conditionally-const calls. if has_const_conditions { - self.check_op(ops::ConditionallyConstCall { callee, args: fn_args }); + self.check_op(ops::ConditionallyConstCall { + callee, + args: fn_args, + span: *fn_span, + call_source, + }); } // At this point, we are calling a function, `callee`, whose `DefId` is known... diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index ebd680ac28a2e..6707ebe7d1c84 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{ suggest_constraining_type_param, }; use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; +use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use rustc_trait_selection::traits::SelectionContext; use tracing::debug; @@ -77,6 +78,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { pub(crate) struct ConditionallyConstCall<'tcx> { pub callee: DefId, pub args: GenericArgsRef<'tcx>, + pub span: Span, + pub call_source: CallSource, } impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { @@ -91,16 +94,22 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx.sess.create_feature_err( - errors::ConditionallyConstCall { - span, - def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args), - def_descr: ccx.tcx.def_descr(self.callee), - kind: ccx.const_kind(), - }, - sym::const_trait_impl, - ) + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { + let mut diag = build_error_for_const_call( + ccx, + self.callee, + self.args, + self.span, + self.call_source, + "conditionally", + |_, _, _| {}, + ); + + // Override code and mention feature. + diag.code(E0658); + add_feature_diagnostics(&mut diag, ccx.tcx.sess, sym::const_trait_impl); + + diag } } @@ -118,210 +127,250 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { - let FnCallNonConst { callee, args, span, call_source } = *self; - let ConstCx { tcx, typing_env, .. } = *ccx; + let tcx = ccx.tcx; let caller = ccx.def_id(); - let diag_trait = |err, self_ty: Ty<'_>, trait_id| { - let trait_ref = TraitRef::from_method(tcx, trait_id, args); - - match self_ty.kind() { - Param(param_ty) => { - debug!(?param_ty); - if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() { - let constraint = with_no_trimmed_paths!(format!( - "~const {}", - trait_ref.print_trait_sugared(), - )); - suggest_constraining_type_param( - tcx, - generics, - err, - param_ty.name.as_str(), - &constraint, - Some(trait_ref.def_id), - None, - ); + let mut err = build_error_for_const_call( + ccx, + self.callee, + self.args, + self.span, + self.call_source, + "non", + |err, self_ty, trait_id| { + // FIXME(const_trait_impl): Do we need any of this on the non-const codepath? + + let trait_ref = TraitRef::from_method(tcx, trait_id, self.args); + + match self_ty.kind() { + Param(param_ty) => { + debug!(?param_ty); + if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() { + let constraint = with_no_trimmed_paths!(format!( + "~const {}", + trait_ref.print_trait_sugared(), + )); + suggest_constraining_type_param( + tcx, + generics, + err, + param_ty.name.as_str(), + &constraint, + Some(trait_ref.def_id), + None, + ); + } } - } - ty::Adt(..) => { - let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - let obligation = - Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - let mut selcx = SelectionContext::new(&infcx); - let implsrc = selcx.select(&obligation); - if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { - // FIXME(const_trait_impl) revisit this - if !tcx.is_const_trait_impl(data.impl_def_id) { - let span = tcx.def_span(data.impl_def_id); - err.subdiagnostic(errors::NonConstImplNote { span }); + ty::Adt(..) => { + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ccx.typing_env); + let obligation = + Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); + let mut selcx = SelectionContext::new(&infcx); + let implsrc = selcx.select(&obligation); + if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { + // FIXME(const_trait_impl) revisit this + if !tcx.is_const_trait_impl(data.impl_def_id) { + let span = tcx.def_span(data.impl_def_id); + err.subdiagnostic(errors::NonConstImplNote { span }); + } } } + _ => {} } - _ => {} + }, + ); + + if let ConstContext::Static(_) = ccx.const_kind() { + err.note(fluent_generated::const_eval_lazy_lock); + } + + err + } +} + +/// Build an error message reporting that a function call is not const (or only +/// conditionally const). In case that this call is desugared (like an operator +/// or sugar from something like a `for` loop), try to build a better error message +/// that doesn't call it a method. +fn build_error_for_const_call<'tcx>( + ccx: &ConstCx<'_, 'tcx>, + callee: DefId, + args: ty::GenericArgsRef<'tcx>, + span: Span, + call_source: CallSource, + non_or_conditionally: &'static str, + note_trait_if_possible: impl FnOnce(&mut Diag<'tcx>, Ty<'tcx>, DefId), +) -> Diag<'tcx> { + let tcx = ccx.tcx; + + let call_kind = + call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None); + + debug!(?call_kind); + + let mut err = match call_kind { + CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { + macro_rules! error { + ($err:ident) => { + tcx.dcx().create_err(errors::$err { + span, + ty: self_ty, + kind: ccx.const_kind(), + non_or_conditionally, + }) + }; } - }; - - let call_kind = - call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None); - - debug!(?call_kind); - - let mut err = match call_kind { - CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { - macro_rules! error { - ($err:ident) => { - tcx.dcx().create_err(errors::$err { - span, - ty: self_ty, - kind: ccx.const_kind(), - }) - }; - } - // Don't point at the trait if this is a desugaring... - // FIXME(const_trait_impl): we could perhaps do this for `Iterator`. - match kind { - CallDesugaringKind::ForLoopIntoIter | CallDesugaringKind::ForLoopNext => { - error!(NonConstForLoopIntoIter) - } - CallDesugaringKind::QuestionBranch => { - error!(NonConstQuestionBranch) - } - CallDesugaringKind::QuestionFromResidual => { - error!(NonConstQuestionFromResidual) - } - CallDesugaringKind::TryBlockFromOutput => { - error!(NonConstTryBlockFromOutput) - } - CallDesugaringKind::Await => { - error!(NonConstAwait) - } + // Don't point at the trait if this is a desugaring... + // FIXME(const_trait_impl): we could perhaps do this for `Iterator`. + match kind { + CallDesugaringKind::ForLoopIntoIter | CallDesugaringKind::ForLoopNext => { + error!(NonConstForLoopIntoIter) + } + CallDesugaringKind::QuestionBranch => { + error!(NonConstQuestionBranch) + } + CallDesugaringKind::QuestionFromResidual => { + error!(NonConstQuestionFromResidual) + } + CallDesugaringKind::TryBlockFromOutput => { + error!(NonConstTryBlockFromOutput) + } + CallDesugaringKind::Await => { + error!(NonConstAwait) } } - CallKind::FnCall { fn_trait_id, self_ty } => { - let note = match self_ty.kind() { - FnDef(def_id, ..) => { - let span = tcx.def_span(*def_id); - if ccx.tcx.is_const_fn(*def_id) { - span_bug!(span, "calling const FnDef errored when it shouldn't"); - } - - Some(errors::NonConstClosureNote::FnDef { span }) + } + CallKind::FnCall { fn_trait_id, self_ty } => { + let note = match self_ty.kind() { + FnDef(def_id, ..) => { + let span = tcx.def_span(*def_id); + if ccx.tcx.is_const_fn(*def_id) { + span_bug!(span, "calling const FnDef errored when it shouldn't"); } - FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr), - Closure(..) => Some(errors::NonConstClosureNote::Closure), - _ => None, - }; - let mut err = tcx.dcx().create_err(errors::NonConstClosure { + Some(errors::NonConstClosureNote::FnDef { span }) + } + FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr), + Closure(..) => Some(errors::NonConstClosureNote::Closure), + _ => None, + }; + + let mut err = tcx.dcx().create_err(errors::NonConstClosure { + span, + kind: ccx.const_kind(), + note, + non_or_conditionally, + }); + + note_trait_if_possible(&mut err, self_ty, fn_trait_id); + err + } + CallKind::Operator { trait_id, self_ty, .. } => { + let mut err = if let CallSource::MatchCmp = call_source { + tcx.dcx().create_err(errors::NonConstMatchEq { span, kind: ccx.const_kind(), - note, - }); - - diag_trait(&mut err, self_ty, fn_trait_id); - err - } - CallKind::Operator { trait_id, self_ty, .. } => { - let mut err = if let CallSource::MatchCmp = call_source { - tcx.dcx().create_err(errors::NonConstMatchEq { - span, - kind: ccx.const_kind(), - ty: self_ty, - }) - } else { - let mut sugg = None; - - if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) { - match (args[0].unpack(), args[1].unpack()) { - (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) - if self_ty == rhs_ty - && self_ty.is_ref() - && self_ty.peel_refs().is_primitive() => - { - let mut num_refs = 0; - let mut tmp_ty = self_ty; - while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { - num_refs += 1; - tmp_ty = *inner_ty; - } - let deref = "*".repeat(num_refs); - - if let Ok(call_str) = - ccx.tcx.sess.source_map().span_to_snippet(span) - { - if let Some(eq_idx) = call_str.find("==") { - if let Some(rhs_idx) = call_str[(eq_idx + 2)..] - .find(|c: char| !c.is_whitespace()) - { - let rhs_pos = span.lo() - + BytePos::from_usize(eq_idx + 2 + rhs_idx); - let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); - sugg = Some(errors::ConsiderDereferencing { - deref, - span: span.shrink_to_lo(), - rhs_span, - }); - } + ty: self_ty, + non_or_conditionally, + }) + } else { + let mut sugg = None; + + if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) { + match (args[0].unpack(), args[1].unpack()) { + (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) + if self_ty == rhs_ty + && self_ty.is_ref() + && self_ty.peel_refs().is_primitive() => + { + let mut num_refs = 0; + let mut tmp_ty = self_ty; + while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { + num_refs += 1; + tmp_ty = *inner_ty; + } + let deref = "*".repeat(num_refs); + + if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) { + if let Some(eq_idx) = call_str.find("==") { + if let Some(rhs_idx) = + call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace()) + { + let rhs_pos = + span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx); + let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); + sugg = Some(errors::ConsiderDereferencing { + deref, + span: span.shrink_to_lo(), + rhs_span, + }); } } } - _ => {} } + _ => {} } - tcx.dcx().create_err(errors::NonConstOperator { - span, - kind: ccx.const_kind(), - sugg, - }) - }; - - diag_trait(&mut err, self_ty, trait_id); - err - } - CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { - // Check first whether the source is accessible (issue #87060) - let target = if tcx.sess.source_map().is_span_accessible(deref_target) { - Some(deref_target) - } else { - None - }; - - let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion { + } + tcx.dcx().create_err(errors::NonConstOperator { span, - ty: self_ty, kind: ccx.const_kind(), - target_ty: deref_target_ty, - deref_target: target, - }); + sugg, + non_or_conditionally, + }) + }; - diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); - err - } - _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { - ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }) - } - _ => ccx.dcx().create_err(errors::NonConstFnCall { + note_trait_if_possible(&mut err, self_ty, trait_id); + err + } + CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { + // Check first whether the source is accessible (issue #87060) + let target = if tcx.sess.source_map().is_span_accessible(deref_target) { + Some(deref_target) + } else { + None + }; + + let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion { span, - def_descr: ccx.tcx.def_descr(callee), - def_path_str: ccx.tcx.def_path_str_with_args(callee, args), + ty: self_ty, kind: ccx.const_kind(), - }), - }; + target_ty: deref_target_ty, + deref_target: target, + non_or_conditionally, + }); + + note_trait_if_possible( + &mut err, + self_ty, + tcx.require_lang_item(LangItem::Deref, Some(span)), + ); + err + } + _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { + ccx.dcx().create_err(errors::NonConstFmtMacroCall { + span, + kind: ccx.const_kind(), + non_or_conditionally, + }) + } + _ => ccx.dcx().create_err(errors::NonConstFnCall { + span, + def_descr: ccx.tcx.def_descr(callee), + def_path_str: ccx.tcx.def_path_str_with_args(callee, args), + kind: ccx.const_kind(), + non_or_conditionally, + }), + }; - err.note(format!( - "calls in {}s are limited to constant functions, \ + err.note(format!( + "calls in {}s are limited to constant functions, \ tuple structs and tuple variants", - ccx.const_kind(), - )); - - if let ConstContext::Static(_) = ccx.const_kind() { - err.note(fluent_generated::const_eval_lazy_lock); - } + ccx.const_kind(), + )); - err - } + err } /// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function. diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 57534540019bb..3fe78171cd944 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -174,16 +174,7 @@ pub(crate) struct NonConstFmtMacroCall { #[primary_span] pub span: Span, pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_conditionally_const_call)] -pub(crate) struct ConditionallyConstCall { - #[primary_span] - pub span: Span, - pub def_path_str: String, - pub def_descr: &'static str, - pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -194,6 +185,7 @@ pub(crate) struct NonConstFnCall { pub def_path_str: String, pub def_descr: &'static str, pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -293,68 +285,75 @@ pub struct RawBytesNote { // FIXME(fee1-dead) do not use stringly typed `ConstContext` #[derive(Diagnostic)] -#[diag(const_eval_match_eq_non_const, code = E0015)] +#[diag(const_eval_non_const_match_eq, code = E0015)] #[note] pub struct NonConstMatchEq<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_for_loop_into_iter_non_const, code = E0015)] +#[diag(const_eval_non_const_for_loop_into_iter, code = E0015)] pub struct NonConstForLoopIntoIter<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_question_branch_non_const, code = E0015)] +#[diag(const_eval_non_const_question_branch, code = E0015)] pub struct NonConstQuestionBranch<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_question_from_residual_non_const, code = E0015)] +#[diag(const_eval_non_const_question_from_residual, code = E0015)] pub struct NonConstQuestionFromResidual<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_try_block_from_output_non_const, code = E0015)] +#[diag(const_eval_non_const_try_block_from_output, code = E0015)] pub struct NonConstTryBlockFromOutput<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_await_non_const, code = E0015)] +#[diag(const_eval_non_const_await, code = E0015)] pub struct NonConstAwait<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_closure_non_const, code = E0015)] +#[diag(const_eval_non_const_closure, code = E0015)] pub struct NonConstClosure { #[primary_span] pub span: Span, pub kind: ConstContext, #[subdiagnostic] pub note: Option, + pub non_or_conditionally: &'static str, } #[derive(Subdiagnostic)] @@ -381,17 +380,18 @@ pub struct ConsiderDereferencing { } #[derive(Diagnostic)] -#[diag(const_eval_operator_non_const, code = E0015)] +#[diag(const_eval_non_const_operator, code = E0015)] pub struct NonConstOperator { #[primary_span] pub span: Span, pub kind: ConstContext, #[subdiagnostic] pub sugg: Option, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_deref_coercion_non_const, code = E0015)] +#[diag(const_eval_non_const_deref_coercion, code = E0015)] #[note] pub struct NonConstDerefCoercion<'tcx> { #[primary_span] @@ -401,6 +401,7 @@ pub struct NonConstDerefCoercion<'tcx> { pub target_ty: Ty<'tcx>, #[note(const_eval_target_note)] pub deref_target: Option, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5421517046d86..3c3bbc8c31d86 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -572,7 +572,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // `#[coroutine]` attribute to be applied to closures to make them coroutines instead gated!( coroutine, Normal, template!(Word), ErrorFollowing, - EncodeCrossCrate::No, coroutines, experimental!(coroutines) + EncodeCrossCrate::No, coroutines, experimental!(coroutine) ), // RFC 3543 diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 0c19e2e4c5184..1569c0963c84b 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1036,7 +1036,7 @@ pub(super) fn const_conditions<'tcx>( icx.lowerer().lower_bounds( tcx.types.self_param, - supertraits.into_iter(), + supertraits, &mut bounds, ty::List::empty(), PredicateFilter::ConstIfConst, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 72a1e4af9bfce..b3d87ef4ad2bf 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1096,7 +1096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) ) { continue; - }; + } match self.tcx.hir().get_if_local(item_def_id) { // Unmet obligation comes from a `derive` macro, point at it once to @@ -1210,8 +1210,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.1.insert((cause_span, "unsatisfied trait bound introduced here")); entry.2.push(p); } - Some(node) => unreachable!("encountered `{node:?}` due to `{cause:#?}`"), - None => (), + _ => { + // It's possible to use well-formedness clauses to get obligations + // which point arbitrary items like ADTs, so there's no use in ICEing + // here if we find that the obligation originates from some other + // node that we don't handle. + } } } let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect(); diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 4185b3f4d4d85..5bd20e00eb68c 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -367,9 +367,8 @@ fn calc_test_vectors_index(conditions: &mut Vec) -> usize { }) .collect::>(); - let mut queue = std::collections::VecDeque::from_iter( - next_conditions.swap_remove(&ConditionId::START).into_iter(), - ); + let mut queue = + std::collections::VecDeque::from_iter(next_conditions.swap_remove(&ConditionId::START)); num_paths_stats[ConditionId::START] = 1; let mut decision_end_nodes = Vec::new(); while let Some(branch) = queue.pop_front() { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 6590702118c7f..50d10883d2cad 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -691,7 +691,7 @@ impl Subdiagnostic for LocalLabel<'_> { for dtor in self.destructors { dtor.add_to_diag_with(diag, f); } - let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue.into()); + let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue); diag.span_label(self.span, msg); } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 26a09f0daca02..b19c9cee75a0b 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -419,7 +419,7 @@ pub mod token_stream { /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. #[unstable(feature = "proc_macro_quote", issue = "54722")] -#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals)] +#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals, proc_macro_totokens)] #[rustc_builtin_macro] pub macro quote($($t:tt)*) { /* compiler built-in */ diff --git a/library/proc_macro/src/quote.rs b/library/proc_macro/src/quote.rs index 04fa696d5e6be..bcb15912bb65e 100644 --- a/library/proc_macro/src/quote.rs +++ b/library/proc_macro/src/quote.rs @@ -4,12 +4,14 @@ //! This quasiquoter uses macros 2.0 hygiene to reliably access //! items from `proc_macro`, to build a `proc_macro::TokenStream`. -use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use crate::{ + Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree, +}; -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; +macro_rules! minimal_quote_tt { + (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) }; + ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, minimal_quote!($($t)*)) }; + ({$($t:tt)*}) => { Group::new(Delimiter::Brace, minimal_quote!($($t)*)) }; (,) => { Punct::new(',', Spacing::Alone) }; (.) => { Punct::new('.', Spacing::Alone) }; (;) => { Punct::new(';', Spacing::Alone) }; @@ -21,21 +23,20 @@ macro_rules! quote_tt { ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; } -macro_rules! quote_ts { +macro_rules! minimal_quote_ts { ((@ $($t:tt)*)) => { $($t)* }; (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() + { + let mut c = ( + TokenTree::from(Punct::new(':', Spacing::Joint)), + TokenTree::from(Punct::new(':', Spacing::Alone)) + ); + c.0.set_span(Span::def_site()); + c.1.set_span(Span::def_site()); + [c.0, c.1].into_iter().collect::() + } }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; + ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) }; } /// Simpler version of the real `quote!` macro, implemented solely @@ -46,12 +47,14 @@ macro_rules! quote_ts { /// /// Note: supported tokens are a subset of the real `quote!`, but /// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { - () => { TokenStream::new() }; +macro_rules! minimal_quote { ($($t:tt)*) => { - [ - $(TokenStream::from(quote_ts!($t)),)* - ].iter().cloned().collect::() + { + #[allow(unused_mut)] // In case the expansion is empty + let mut ts = TokenStream::new(); + $(ToTokens::to_tokens(&minimal_quote_ts!($t), &mut ts);)* + ts + } }; } @@ -62,52 +65,66 @@ macro_rules! quote { #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote(stream: TokenStream) -> TokenStream { if stream.is_empty() { - return quote!(crate::TokenStream::new()); + return minimal_quote!(crate::TokenStream::new()); } - let proc_macro_crate = quote!(crate); + let proc_macro_crate = minimal_quote!(crate); let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; + + let mut tokens = crate::TokenStream::new(); + for tree in stream { + if after_dollar { + after_dollar = false; + match tree { + TokenTree::Ident(_) => { + minimal_quote!(crate::ToTokens::to_tokens(&(@ tree), &mut ts);) + .to_tokens(&mut tokens); + continue; } + TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} + _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), } + } else if let TokenTree::Punct(ref tt) = tree { + if tt.as_char() == '$' { + after_dollar = true; + continue; + } + } - Some(quote!(crate::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(crate::TokenTree::Punct(crate::Punct::new( + match tree { + TokenTree::Punct(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new( (@ TokenTree::from(Literal::character(tt.as_char()))), (@ match tt.spacing() { - Spacing::Alone => quote!(crate::Spacing::Alone), - Spacing::Joint => quote!(crate::Spacing::Joint), + Spacing::Alone => minimal_quote!(crate::Spacing::Alone), + Spacing::Joint => minimal_quote!(crate::Spacing::Joint), }), - ))), - TokenTree::Group(tt) => quote!(crate::TokenTree::Group(crate::Group::new( + )), &mut ts);) + } + TokenTree::Group(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Group(crate::Group::new( (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(crate::Delimiter::Parenthesis), - Delimiter::Brace => quote!(crate::Delimiter::Brace), - Delimiter::Bracket => quote!(crate::Delimiter::Bracket), - Delimiter::None => quote!(crate::Delimiter::None), + Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis), + Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace), + Delimiter::Bracket => minimal_quote!(crate::Delimiter::Bracket), + Delimiter::None => minimal_quote!(crate::Delimiter::None), }), (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), + )), &mut ts);) + } + TokenTree::Ident(tt) => { + let literal = tt.to_string(); + let (literal, ctor) = if let Some(stripped) = literal.strip_prefix("r#") { + (stripped, minimal_quote!(crate::Ident::new_raw)) + } else { + (literal.as_str(), minimal_quote!(crate::Ident::new)) + }; + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident((@ ctor)( + (@ TokenTree::from(Literal::string(literal))), (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({ + )), &mut ts);) + } + TokenTree::Literal(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Literal({ let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) .parse::() .unwrap() @@ -120,16 +137,22 @@ pub fn quote(stream: TokenStream) -> TokenStream { } else { unreachable!() } - })) - })),)) - }) - .collect::(); - + }), &mut ts);) + } + } + .to_tokens(&mut tokens); + } if after_dollar { panic!("unexpected trailing `$` in `quote!`"); } - quote!([(@ tokens)].iter().cloned().collect::()) + minimal_quote! { + { + let mut ts = crate::TokenStream::new(); + (@ tokens) + ts + } + } } /// Quote a `Span` into a `TokenStream`. @@ -137,5 +160,5 @@ pub fn quote(stream: TokenStream) -> TokenStream { #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) + minimal_quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index e360ba0f6d7d8..f657f82e6e368 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -130,25 +130,27 @@ impl Thread { } } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"))] pub fn set_name(name: &CStr) { - const TASK_COMM_LEN: usize = 16; - unsafe { - // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20. - let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + // Linux limits the allowed length of the name. + const TASK_COMM_LEN: usize = 16; + let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); + } else { + // FreeBSD and DragonFly BSD do not enforce length limits. + } + }; + // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux, + // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0. let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. debug_assert_eq!(res, 0); } } - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "nuttx" - ))] + #[cfg(any(target_os = "openbsd", target_os = "nuttx"))] pub fn set_name(name: &CStr) { unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index b55469f332aa1..1d88726d94586 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -31,18 +31,31 @@ use crate::utils::{format_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident}; /// - `[small, ntp]` /// - unary tuple constructor `([small, ntp])` /// - `&[small]` -pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool { +pub(crate) fn is_short_pattern( + context: &RewriteContext<'_>, + pat: &ast::Pat, + pat_str: &str, +) -> bool { // We also require that the pattern is reasonably 'small' with its literal width. - pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat) + pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(context, pat) } -fn is_short_pattern_inner(pat: &ast::Pat) -> bool { - match pat.kind { - ast::PatKind::Rest - | ast::PatKind::Never - | ast::PatKind::Wild - | ast::PatKind::Err(_) - | ast::PatKind::Expr(_) => true, +fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool { + match &pat.kind { + ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => { + true + } + ast::PatKind::Expr(expr) => match &expr.kind { + ast::ExprKind::Lit(_) => true, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind { + ast::ExprKind::Lit(_) => true, + _ => unreachable!(), + }, + ast::ExprKind::ConstBlock(_) | ast::ExprKind::Path(..) => { + context.config.style_edition() <= StyleEdition::Edition2024 + } + _ => unreachable!(), + }, ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -57,8 +70,8 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool { ast::PatKind::Box(ref p) | PatKind::Deref(ref p) | ast::PatKind::Ref(ref p, _) - | ast::PatKind::Paren(ref p) => is_short_pattern_inner(&*p), - PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)), + | ast::PatKind::Paren(ref p) => is_short_pattern_inner(context, &*p), + PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(context, p)), } } @@ -96,7 +109,7 @@ impl Rewrite for Pat { let use_mixed_layout = pats .iter() .zip(pat_strs.iter()) - .all(|(pat, pat_str)| is_short_pattern(pat, pat_str)); + .all(|(pat, pat_str)| is_short_pattern(context, pat, pat_str)); let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect(); let tactic = if use_mixed_layout { DefinitiveListTactic::Mixed diff --git a/src/tools/rustfmt/tests/source/pattern.rs b/src/tools/rustfmt/tests/source/pattern.rs index f06d03cadf2f7..ed6ad690fa98d 100644 --- a/src/tools/rustfmt/tests/source/pattern.rs +++ b/src/tools/rustfmt/tests/source/pattern.rs @@ -88,3 +88,13 @@ fn issue3728() { | c; foo((1,)); } + +fn literals() { + match 42 { + const { 1 + 2 } | 4 + | 6 => {} + 10 | 11 | 12 + | 13 | 14 => {} + _ => {} + } +} \ No newline at end of file diff --git a/src/tools/rustfmt/tests/target/pattern.rs b/src/tools/rustfmt/tests/target/pattern.rs index 576018ac623fd..e867f65929dd9 100644 --- a/src/tools/rustfmt/tests/target/pattern.rs +++ b/src/tools/rustfmt/tests/target/pattern.rs @@ -96,3 +96,11 @@ fn issue3728() { let foo = |(c,)| c; foo((1,)); } + +fn literals() { + match 42 { + const { 1 + 2 } | 4 | 6 => {} + 10 | 11 | 12 | 13 | 14 => {} + _ => {} + } +} diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr index 322259cf2f84f..0491bdbc2e17a 100644 --- a/tests/ui/coroutine/gen_block.e2024.stderr +++ b/tests/ui/coroutine/gen_block.e2024.stderr @@ -1,4 +1,4 @@ -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:20:13 | LL | let _ = #[coroutine] || yield true; @@ -8,7 +8,7 @@ LL | let _ = #[coroutine] || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:24:13 | LL | let _ = #[coroutine] || {}; diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr index 15123a49e4855..43437793005a5 100644 --- a/tests/ui/coroutine/gen_block.none.stderr +++ b/tests/ui/coroutine/gen_block.none.stderr @@ -44,7 +44,7 @@ LL | let _ = #[coroutine] || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:20:13 | LL | let _ = #[coroutine] || yield true; @@ -54,7 +54,7 @@ LL | let _ = #[coroutine] || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:24:13 | LL | let _ = #[coroutine] || {}; diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs index 6734de3b667d2..4494d654eeb62 100644 --- a/tests/ui/coroutine/gen_block.rs +++ b/tests/ui/coroutine/gen_block.rs @@ -18,9 +18,9 @@ fn main() { //~^^ ERROR `yield` can only be used in let _ = #[coroutine] || yield true; //[none]~ ERROR yield syntax is experimental - //~^ ERROR `#[coroutines]` attribute is an experimental feature + //~^ ERROR `#[coroutine]` attribute is an experimental feature //~^^ ERROR yield syntax is experimental let _ = #[coroutine] || {}; - //~^ ERROR `#[coroutines]` attribute is an experimental feature + //~^ ERROR `#[coroutine]` attribute is an experimental feature } diff --git a/tests/ui/issues/issue-25901.rs b/tests/ui/issues/issue-25901.rs index eae038c71a0ea..bfcee1ac503a2 100644 --- a/tests/ui/issues/issue-25901.rs +++ b/tests/ui/issues/issue-25901.rs @@ -2,7 +2,7 @@ struct A; struct B; static S: &'static B = &A; -//~^ ERROR cannot call conditionally-const method +//~^ ERROR cannot perform conditionally-const deref coercion use std::ops::Deref; diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr index 655a8b78c6a1e..a954f38af8397 100644 --- a/tests/ui/issues/issue-25901.stderr +++ b/tests/ui/issues/issue-25901.stderr @@ -1,9 +1,16 @@ -error[E0658]: cannot call conditionally-const method `::deref` in statics +error[E0658]: cannot perform conditionally-const deref coercion on `A` in statics --> $DIR/issue-25901.rs:4:24 | LL | static S: &'static B = &A; | ^^ | + = note: attempting to deref into `B` +note: deref defined here + --> $DIR/issue-25901.rs:10:5 + | +LL | type Target = B; + | ^^^^^^^^^^^ + = note: calls in statics are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/methods/bad-wf-when-selecting-method.rs b/tests/ui/methods/bad-wf-when-selecting-method.rs new file mode 100644 index 0000000000000..638d1ffa982fa --- /dev/null +++ b/tests/ui/methods/bad-wf-when-selecting-method.rs @@ -0,0 +1,18 @@ +trait Wf { + type Assoc; +} + +struct Wrapper, U>(T); + +trait Trait { + fn needs_sized(self); +} + +fn test(t: T) { + Wrapper(t).needs_sized(); + //~^ ERROR the trait bound `T: Wf` is not satisfied + //~| ERROR the trait bound `T: Wf` is not satisfied + //~| the method `needs_sized` exists for struct `Wrapper`, but its trait bounds were not satisfied +} + +fn main() {} diff --git a/tests/ui/methods/bad-wf-when-selecting-method.stderr b/tests/ui/methods/bad-wf-when-selecting-method.stderr new file mode 100644 index 0000000000000..e6d500349670c --- /dev/null +++ b/tests/ui/methods/bad-wf-when-selecting-method.stderr @@ -0,0 +1,54 @@ +error[E0277]: the trait bound `T: Wf` is not satisfied + --> $DIR/bad-wf-when-selecting-method.rs:12:13 + | +LL | Wrapper(t).needs_sized(); + | ------- ^ the trait `Wf` is not implemented for `T` + | | + | required by a bound introduced by this call + | +note: required by a bound in `Wrapper` + --> $DIR/bad-wf-when-selecting-method.rs:5:19 + | +LL | struct Wrapper, U>(T); + | ^^^^^^^^^^^^^ required by this bound in `Wrapper` +help: consider restricting type parameter `T` with trait `Wf` + | +LL | fn test(t: T) { + | ++++ + +error[E0277]: the trait bound `T: Wf` is not satisfied + --> $DIR/bad-wf-when-selecting-method.rs:12:5 + | +LL | Wrapper(t).needs_sized(); + | ^^^^^^^^^^ the trait `Wf` is not implemented for `T` + | +note: required by a bound in `Wrapper` + --> $DIR/bad-wf-when-selecting-method.rs:5:19 + | +LL | struct Wrapper, U>(T); + | ^^^^^^^^^^^^^ required by this bound in `Wrapper` +help: consider restricting type parameter `T` with trait `Wf` + | +LL | fn test(t: T) { + | ++++ + +error[E0599]: the method `needs_sized` exists for struct `Wrapper`, but its trait bounds were not satisfied + --> $DIR/bad-wf-when-selecting-method.rs:12:16 + | +LL | struct Wrapper, U>(T); + | ----------------------------------- method `needs_sized` not found for this struct +... +LL | Wrapper(t).needs_sized(); + | ^^^^^^^^^^^ method cannot be called on `Wrapper` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `T: Wf` +help: consider restricting the type parameter to satisfy the trait bound + | +LL | fn test(t: T) where T: Wf { + | +++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/proc-macro/quote-debug.stdout b/tests/ui/proc-macro/quote-debug.stdout deleted file mode 100644 index d84b4e051e872..0000000000000 --- a/tests/ui/proc-macro/quote-debug.stdout +++ /dev/null @@ -1,49 +0,0 @@ -#![feature(prelude_import)] -#![no_std] -//@ check-pass -//@ force-host -//@ no-prefer-dynamic -//@ compile-flags: -Z unpretty=expanded -//@ needs-unwind compiling proc macros with panic=abort causes a warning -// -// This file is not actually used as a proc-macro - instead, -// it's just used to show the output of the `quote!` macro - -#![feature(proc_macro_quote)] -#![crate_type = "proc-macro"] -#[prelude_import] -use ::std::prelude::rust_2015::*; -#[macro_use] -extern crate std; - -extern crate proc_macro; - -fn main() { - [crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let", - crate::Span::recover_proc_macro_span(0)))), - crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello", - crate::Span::recover_proc_macro_span(1)))), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('=', - crate::Spacing::Alone))), - crate::TokenStream::from(crate::TokenTree::Literal({ - let mut iter = - "\"world\"".parse::().unwrap().into_iter(); - if let (Some(crate::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) { - lit.set_span(crate::Span::recover_proc_macro_span(2)); - lit - } else { - ::core::panicking::panic("internal error: entered unreachable code") - } - })), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new(';', - crate::Spacing::Alone)))].iter().cloned().collect::() -} -const _: () = - { - extern crate proc_macro; - #[rustc_proc_macro_decls] - #[used] - #[allow(deprecated)] - static _DECLS: &[proc_macro::bridge::client::ProcMacro] = &[]; - }; diff --git a/tests/ui/proc-macro/quote/auxiliary/basic.rs b/tests/ui/proc-macro/quote/auxiliary/basic.rs new file mode 100644 index 0000000000000..ef726bbfbe3a0 --- /dev/null +++ b/tests/ui/proc-macro/quote/auxiliary/basic.rs @@ -0,0 +1,361 @@ +#![feature(proc_macro_quote)] +#![feature(proc_macro_totokens)] + +extern crate proc_macro; + +use std::borrow::Cow; +use std::ffi::{CStr, CString}; + +use proc_macro::*; + +#[proc_macro] +pub fn run_tests(_: TokenStream) -> TokenStream { + test_quote_impl(); + test_substitution(); + test_advanced(); + test_integer(); + test_floating(); + test_char(); + test_str(); + test_string(); + test_c_str(); + test_c_string(); + test_interpolated_literal(); + test_ident(); + test_underscore(); + test_duplicate(); + test_empty_quote(); + test_box_str(); + test_cow(); + test_append_tokens(); + test_outer_line_comment(); + test_inner_line_comment(); + test_outer_block_comment(); + test_inner_block_comment(); + test_outer_attr(); + test_inner_attr(); + test_quote_raw_id(); + + TokenStream::new() +} + +// Based on https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/tests/test.rs +// +// FIXME(quote): +// The following tests are removed because they are not supported yet in `proc_macro::quote!` +// +// - quote_spanned: +// - fn test_quote_spanned_impl +// - fn test_type_inference_for_span +// - wrong-type-span.rs +// - format_ident: +// - fn test_format_ident +// - fn test_format_ident_strip_raw +// - repetition: +// - fn test_iter +// - fn test_array +// - fn test_fancy_repetition +// - fn test_nested_fancy_repetition +// - fn test_duplicate_name_repetition +// - fn test_duplicate_name_repetition_no_copy +// - fn test_btreeset_repetition +// - fn test_variable_name_conflict +// - fn test_nonrep_in_repetition +// - fn test_closure +// - fn test_star_after_repetition + +struct X; + +impl ToTokens for X { + fn to_tokens(&self, tokens: &mut TokenStream) { + Ident::new("X", Span::call_site()).to_tokens(tokens) + } +} + +fn test_quote_impl() { + let tokens = quote! { + impl<'a, T: ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } + } + }; + + let expected = r#"impl < 'a, T : ToTokens > ToTokens for & 'a T +{ + fn to_tokens(& self, tokens : & mut TokenStream) + { (** self).to_tokens(tokens) } +}"#; + + assert_eq!(expected, tokens.to_string()); +} + +fn test_substitution() { + let x = X; + let tokens = quote!($x <$x> ($x) [$x] {$x}); + + let expected = "X (X) [X] { X }"; + + assert_eq!(expected, tokens.to_string()); +} + +fn test_advanced() { + let generics = quote!( <'a, T> ); + + let where_clause = quote!( where T: Serialize ); + + let field_ty = quote!(String); + + let item_ty = quote!(Cow<'a, str>); + + let path = quote!(SomeTrait::serialize_with); + + let value = quote!(self.x); + + let tokens = quote! { + struct SerializeWith $generics $where_clause { + value: &'a $field_ty, + phantom: ::std::marker::PhantomData<$item_ty>, + } + + impl $generics ::serde::Serialize for SerializeWith $generics $where_clause { + fn serialize(&self, s: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer + { + $path(self.value, s) + } + } + + SerializeWith { + value: $value, + phantom: ::std::marker::PhantomData::<$item_ty>, + } + }; + + let expected = r#"struct SerializeWith < 'a, T > where T : Serialize +{ + value : & 'a String, phantom : :: std :: marker :: PhantomData >, +} impl < 'a, T > :: serde :: Serialize for SerializeWith < 'a, T > where T : +Serialize +{ + fn serialize < S > (& self, s : & mut S) -> Result < (), S :: Error > + where S : :: serde :: Serializer + { SomeTrait :: serialize_with(self.value, s) } +} SerializeWith +{ + value : self.x, phantom : :: std :: marker :: PhantomData :: >, +}"#; + + assert_eq!(expected, tokens.to_string()); +} + +fn test_integer() { + let ii8 = -1i8; + let ii16 = -1i16; + let ii32 = -1i32; + let ii64 = -1i64; + let ii128 = -1i128; + let iisize = -1isize; + let uu8 = 1u8; + let uu16 = 1u16; + let uu32 = 1u32; + let uu64 = 1u64; + let uu128 = 1u128; + let uusize = 1usize; + + let tokens = quote! { + 1 1i32 1u256 + $ii8 $ii16 $ii32 $ii64 $ii128 $iisize + $uu8 $uu16 $uu32 $uu64 $uu128 $uusize + }; + let expected = r#"1 1i32 1u256 -1i8 -1i16 -1i32 -1i64 -1i128 -1isize 1u8 1u16 1u32 1u64 1u128 +1usize"#; + assert_eq!(expected, tokens.to_string()); +} + +fn test_floating() { + let e32 = 2.345f32; + + let e64 = 2.345f64; + + let tokens = quote! { + $e32 + $e64 + }; + let expected = concat!("2.345f32 2.345f64"); + assert_eq!(expected, tokens.to_string()); +} + +fn test_char() { + let zero = '\u{1}'; + let dollar = '$'; + let pound = '#'; + let quote = '"'; + let apost = '\''; + let newline = '\n'; + let heart = '\u{2764}'; + + let tokens = quote! { + $zero $dollar $pound $quote $apost $newline $heart + }; + let expected = "'\\u{1}' '$' '#' '\"' '\\'' '\\n' '\u{2764}'"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_str() { + let s = "\u{1} a 'b \" c"; + let tokens = quote!($s); + let expected = "\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_string() { + let s = "\u{1} a 'b \" c".to_string(); + let tokens = quote!($s); + let expected = "\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_c_str() { + let s = CStr::from_bytes_with_nul(b"\x01 a 'b \" c\0").unwrap(); + let tokens = quote!($s); + let expected = "c\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_c_string() { + let s = CString::new(&b"\x01 a 'b \" c"[..]).unwrap(); + let tokens = quote!($s); + let expected = "c\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_interpolated_literal() { + macro_rules! m { + ($literal:literal) => { + quote!($literal) + }; + } + + let tokens = m!(1); + let expected = "1"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(-1); + let expected = "- 1"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(true); + let expected = "true"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(-true); + let expected = "- true"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_ident() { + let foo = Ident::new("Foo", Span::call_site()); + let bar = Ident::new(&format!("Bar{}", 7), Span::call_site()); + let tokens = quote!(struct $foo; enum $bar {}); + let expected = "struct Foo; enum Bar7 {}"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_underscore() { + let tokens = quote!(let _;); + let expected = "let _;"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_duplicate() { + let ch = 'x'; + + let tokens = quote!($ch $ch); + + let expected = "'x' 'x'"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_empty_quote() { + let tokens = quote!(); + assert_eq!("", tokens.to_string()); +} + +fn test_box_str() { + let b = "str".to_owned().into_boxed_str(); + let tokens = quote! { $b }; + assert_eq!("\"str\"", tokens.to_string()); +} + +fn test_cow() { + let owned: Cow = Cow::Owned(Ident::new("owned", Span::call_site())); + + let ident = Ident::new("borrowed", Span::call_site()); + let borrowed = Cow::Borrowed(&ident); + + let tokens = quote! { $owned $borrowed }; + assert_eq!("owned borrowed", tokens.to_string()); +} + +fn test_append_tokens() { + let mut a = quote!(a); + let b = quote!(b); + a.extend(b); + assert_eq!("a b", a.to_string()); +} + +fn test_outer_line_comment() { + let tokens = quote! { + /// doc + }; + let expected = "#[doc = \" doc\"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_inner_line_comment() { + let tokens = quote! { + //! doc + }; + let expected = "# ! [doc = \" doc\"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_outer_block_comment() { + let tokens = quote! { + /** doc */ + }; + let expected = "#[doc = \" doc \"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_inner_block_comment() { + let tokens = quote! { + /*! doc */ + }; + let expected = "# ! [doc = \" doc \"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_outer_attr() { + let tokens = quote! { + #[inline] + }; + let expected = "#[inline]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_inner_attr() { + let tokens = quote! { + #![no_std] + }; + let expected = "#! [no_std]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_quote_raw_id() { + let id = quote!(r#raw_id); + assert_eq!(id.to_string(), "r#raw_id"); +} diff --git a/tests/ui/proc-macro/quote/basic.rs b/tests/ui/proc-macro/quote/basic.rs new file mode 100644 index 0000000000000..0336dbb785623 --- /dev/null +++ b/tests/ui/proc-macro/quote/basic.rs @@ -0,0 +1,8 @@ +//@ run-pass +//@ proc-macro: basic.rs + +extern crate basic; + +fn main() { + basic::run_tests!(); +} diff --git a/tests/ui/proc-macro/quote-debug.rs b/tests/ui/proc-macro/quote/debug.rs similarity index 91% rename from tests/ui/proc-macro/quote-debug.rs rename to tests/ui/proc-macro/quote/debug.rs index 11d144d609f5a..ce113079e5678 100644 --- a/tests/ui/proc-macro/quote-debug.rs +++ b/tests/ui/proc-macro/quote/debug.rs @@ -15,5 +15,6 @@ extern crate proc_macro; fn main() { proc_macro::quote! { let hello = "world"; + let r#raw_ident = r#"raw"literal"#; } } diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout new file mode 100644 index 0000000000000..3eaad9eb96997 --- /dev/null +++ b/tests/ui/proc-macro/quote/debug.stdout @@ -0,0 +1,72 @@ +#![feature(prelude_import)] +#![no_std] +//@ check-pass +//@ force-host +//@ no-prefer-dynamic +//@ compile-flags: -Z unpretty=expanded +//@ needs-unwind compiling proc macros with panic=abort causes a warning +// +// This file is not actually used as a proc-macro - instead, +// it's just used to show the output of the `quote!` macro + +#![feature(proc_macro_quote)] +#![crate_type = "proc-macro"] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +extern crate proc_macro; + +fn main() { + { + let mut ts = crate::TokenStream::new(); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("let", + crate::Span::recover_proc_macro_span(0))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("hello", + crate::Span::recover_proc_macro_span(1))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new('=', + crate::Spacing::Alone)), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Literal({ + let mut iter = + "\"world\"".parse::().unwrap().into_iter(); + if let (Some(crate::TokenTree::Literal(mut lit)), None) = + (iter.next(), iter.next()) { + lit.set_span(crate::Span::recover_proc_macro_span(2)); + lit + } else { + ::core::panicking::panic("internal error: entered unreachable code") + } + }), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';', + crate::Spacing::Alone)), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("let", + crate::Span::recover_proc_macro_span(3))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new_raw("raw_ident", + crate::Span::recover_proc_macro_span(4))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new('=', + crate::Spacing::Alone)), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Literal({ + let mut iter = + "r#\"raw\"literal\"#".parse::().unwrap().into_iter(); + if let (Some(crate::TokenTree::Literal(mut lit)), None) = + (iter.next(), iter.next()) { + lit.set_span(crate::Span::recover_proc_macro_span(5)); + lit + } else { + ::core::panicking::panic("internal error: entered unreachable code") + } + }), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';', + crate::Spacing::Alone)), &mut ts); + ts + } +} +const _: () = + { + extern crate proc_macro; + #[rustc_proc_macro_decls] + #[used] + #[allow(deprecated)] + static _DECLS: &[proc_macro::bridge::client::ProcMacro] = &[]; + }; diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs new file mode 100644 index 0000000000000..2f67ae1bc6edc --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs @@ -0,0 +1,17 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!($($nonrep $nonrep)*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr new file mode 100644 index 0000000000000..5f28a46f3181d --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter-interpolated-dup.rs:16:5 + | +LL | quote!($($nonrep $nonrep)*); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs new file mode 100644 index 0000000000000..1efb3eac64247 --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs @@ -0,0 +1,17 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!($($nonrep)*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr new file mode 100644 index 0000000000000..595aa8587634a --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter-interpolated.rs:16:5 + | +LL | quote!($($nonrep)*); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs new file mode 100644 index 0000000000000..5f2ddabc390da --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs @@ -0,0 +1,13 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + quote!($(a b),*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr new file mode 100644 index 0000000000000..f6f5d7e007d0f --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter-separated.rs:12:5 + | +LL | quote!($(a b),*); + | ^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.rs b/tests/ui/proc-macro/quote/does-not-have-iter.rs new file mode 100644 index 0000000000000..25ffd786cc614 --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter.rs @@ -0,0 +1,13 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + quote!($(a b)*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.stderr b/tests/ui/proc-macro/quote/does-not-have-iter.stderr new file mode 100644 index 0000000000000..0ed1daffc8cdf --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter.rs:12:5 + | +LL | quote!($(a b)*); + | ^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/not-quotable.rs b/tests/ui/proc-macro/quote/not-quotable.rs new file mode 100644 index 0000000000000..7e38b4410528a --- /dev/null +++ b/tests/ui/proc-macro/quote/not-quotable.rs @@ -0,0 +1,12 @@ +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use std::net::Ipv4Addr; + +use proc_macro::quote; + +fn main() { + let ip = Ipv4Addr::LOCALHOST; + let _ = quote! { $ip }; //~ ERROR the trait bound `Ipv4Addr: ToTokens` is not satisfied +} diff --git a/tests/ui/proc-macro/quote/not-quotable.stderr b/tests/ui/proc-macro/quote/not-quotable.stderr new file mode 100644 index 0000000000000..e349b2dce5300 --- /dev/null +++ b/tests/ui/proc-macro/quote/not-quotable.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied + --> $DIR/not-quotable.rs:11:13 + | +LL | let _ = quote! { $ip }; + | ^^^^^^^^^^^^^^ + | | + | the trait `ToTokens` is not implemented for `Ipv4Addr` + | required by a bound introduced by this call + | + = help: the following other types implement trait `ToTokens`: + &T + &mut T + Box + CString + Cow<'_, T> + Option + Rc + bool + and 24 others + = note: this error originates in the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/proc-macro/quote/not-repeatable.rs b/tests/ui/proc-macro/quote/not-repeatable.rs new file mode 100644 index 0000000000000..d115da7318156 --- /dev/null +++ b/tests/ui/proc-macro/quote/not-repeatable.rs @@ -0,0 +1,16 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +struct Ipv4Addr; + +fn main() { + let ip = Ipv4Addr; + let _ = quote! { $($ip)* }; +} diff --git a/tests/ui/proc-macro/quote/not-repeatable.stderr b/tests/ui/proc-macro/quote/not-repeatable.stderr new file mode 100644 index 0000000000000..18fbcd7379858 --- /dev/null +++ b/tests/ui/proc-macro/quote/not-repeatable.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/not-repeatable.rs:15:13 + | +LL | let _ = quote! { $($ip)* }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index cf4c219215e08..90b63249eca1a 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -4,6 +4,7 @@ error[E0658]: cannot call conditionally-const method `::deref` in co LL | self.0 | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr index 09bf9c023c843..7cdde5a079f2d 100644 --- a/tests/ui/traits/const-traits/cross-crate.stock.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr @@ -1,9 +1,10 @@ error[E0658]: cannot call conditionally-const method `::func` in constant functions - --> $DIR/cross-crate.rs:22:5 + --> $DIR/cross-crate.rs:22:11 | LL | Const.func(); - | ^^^^^^^^^^^^ + | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr index e52e5609b01d4..2358731c901f6 100644 --- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr @@ -1,19 +1,21 @@ error[E0658]: cannot call conditionally-const method `::func` in constant functions - --> $DIR/cross-crate.rs:19:5 + --> $DIR/cross-crate.rs:19:14 | LL | NonConst.func(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: cannot call conditionally-const method `::func` in constant functions - --> $DIR/cross-crate.rs:22:5 + --> $DIR/cross-crate.rs:22:11 | LL | Const.func(); - | ^^^^^^^^^^^^ + | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr index bf7466b8e1666..400c76fcaf494 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -4,6 +4,7 @@ error[E0658]: cannot call conditionally-const associated function ` for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr index 8abda1c8f8afe..024db4b6d68d0 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr @@ -39,11 +39,12 @@ LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: cannot call conditionally-const method `::a` in constant functions - --> $DIR/super-traits-fail-3.rs:36:5 + --> $DIR/super-traits-fail-3.rs:36:7 | LL | x.a(); - | ^^^^^ + | ^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr index 8abda1c8f8afe..024db4b6d68d0 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr @@ -39,11 +39,12 @@ LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: cannot call conditionally-const method `::a` in constant functions - --> $DIR/super-traits-fail-3.rs:36:5 + --> $DIR/super-traits-fail-3.rs:36:7 | LL | x.a(); - | ^^^^^ + | ^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date