diff --git a/Cargo.lock b/Cargo.lock index 4adee6166f7b7..c97c4a123e92c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4497,7 +4497,6 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index a5cc8d9ea012c..1071105522d11 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 74e38f525c8e6..cf6dd40718b3d 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -148,9 +148,6 @@ trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement -trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` - .label = empty on-clause here - trait_selection_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` trait_selection_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type @@ -187,9 +184,6 @@ trait_selection_inherent_projection_normalization_overflow = overflow evaluating trait_selection_invalid_format_specifier = invalid format specifier .help = no format specifier are supported in this position -trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` - .label = invalid on-clause here - trait_selection_label_bad = {$bad_kind -> *[other] cannot infer type [more_info] cannot infer {$prefix_kind -> @@ -237,10 +231,6 @@ trait_selection_negative_positive_conflict = found both positive and negative im .positive_implementation_here = positive implementation here .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}` -trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value - .label = expected value here - .note = eg `#[rustc_on_unimplemented(message="foo")]` - trait_selection_nothing = {""} trait_selection_oc_cant_coerce_force_inline = @@ -339,6 +329,22 @@ trait_selection_ril_introduced_by = requirement introduced by this return type trait_selection_ril_introduced_here = `'static` requirement introduced here trait_selection_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type +trait_selection_rustc_on_unimplemented_empty_on_clause = empty `on`-clause in `#[rustc_on_unimplemented]` + .label = empty `on`-clause here +trait_selection_rustc_on_unimplemented_expected_identifier = expected an identifier inside this `on`-clause + .label = expected an identifier here, not `{$path}` +trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not = expected a single predicate in `not(..)` + .label = unexpected quantity of predicates here +trait_selection_rustc_on_unimplemented_invalid_flag = invalid flag in `on`-clause + .label = expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}` +trait_selection_rustc_on_unimplemented_invalid_predicate = this predicate is invalid + .label = expected one of `any`, `all` or `not` here, not `{$invalid_pred}` +trait_selection_rustc_on_unimplemented_missing_value = this attribute must have a value + .label = expected value here + .note = e.g. `#[rustc_on_unimplemented(message="foo")]` +trait_selection_rustc_on_unimplemented_unsupported_literal_in_on = literals inside `on`-clauses are not supported + .label = unexpected literal here + trait_selection_source_kind_closure_return = try giving this closure an explicit return type diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 4c4491269b757..d5ee6e2123a19 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{AttrArgs, Attribute}; use rustc_macros::LintDiagnostic; @@ -13,17 +14,16 @@ use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKin use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; -use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; -use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions}; +use crate::error_reporting::traits::on_unimplemented_condition::{ + ConditionOptions, OnUnimplementedCondition, +}; use crate::error_reporting::traits::on_unimplemented_format::{ Ctx, FormatArgs, FormatString, FormatWarning, }; -use crate::errors::{ - EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, -}; +use crate::errors::{InvalidOnClause, NoValueInOnUnimplemented}; use crate::infer::InferCtxtExt; impl<'tcx> TypeErrCtxt<'_, 'tcx> { @@ -306,21 +306,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString { /// Symbol of the format string, i.e. `"content"` - pub symbol: Symbol, + symbol: Symbol, ///The span of the format string, i.e. `"content"` - pub span: Span, - pub is_diagnostic_namespace_variant: bool, + span: Span, + is_diagnostic_namespace_variant: bool, } #[derive(Debug)] pub struct OnUnimplementedDirective { - pub condition: Option, - pub subcommands: Vec, - pub message: Option<(Span, OnUnimplementedFormatString)>, - pub label: Option<(Span, OnUnimplementedFormatString)>, - pub notes: Vec, - pub parent_label: Option, - pub append_const_msg: Option, + condition: Option, + subcommands: Vec, + message: Option<(Span, OnUnimplementedFormatString)>, + label: Option<(Span, OnUnimplementedFormatString)>, + notes: Vec, + parent_label: Option, + append_const_msg: Option, } /// For the `#[rustc_on_unimplemented]` attribute @@ -427,18 +427,12 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))? - .meta_item_or_bool() - .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?; - attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| { - if let Some(value) = cfg.value - && let Err(guar) = parse_value(value, cfg.span) - { - errored = Some(guar); - } - true - }); - Some(Condition { inner: cond.clone() }) + .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?; + + match OnUnimplementedCondition::parse(cond) { + Ok(condition) => Some(condition), + Err(e) => return Err(tcx.dcx().emit_err(e)), + } }; let mut message = None; @@ -724,7 +718,7 @@ impl<'tcx> OnUnimplementedDirective { result } - pub fn evaluate( + pub(crate) fn evaluate( &self, tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -744,7 +738,7 @@ impl<'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { debug!(?command); if let Some(ref condition) = command.condition - && !condition.matches_predicate(tcx, condition_options) + && !condition.matches_predicate(condition_options) { debug!("evaluate: skipping {:?} due to condition", command); continue; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index 116cfb01cb631..13753761f0923 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -1,52 +1,251 @@ -use rustc_ast::MetaItemInner; -use rustc_attr_parsing as attr; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_ast::{MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; -use rustc_span::{DesugaringKind, Span, Symbol, kw, sym}; +use rustc_span::{DesugaringKind, Ident, Span, Symbol, kw, sym}; -/// A predicate in an attribute using on, all, any, -/// similar to a cfg predicate. +use crate::errors::InvalidOnClause; + +/// Represents the `on` filter in `#[rustc_on_unimplemented]`. #[derive(Debug)] -pub struct Condition { - pub inner: MetaItemInner, +pub(crate) struct OnUnimplementedCondition { + span: Span, + pred: Predicate, } -impl Condition { - pub fn span(&self) -> Span { - self.inner.span() +impl OnUnimplementedCondition { + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn matches_predicate(&self, options: &ConditionOptions) -> bool { + self.pred.eval(&mut |p| match p { + FlagOrNv::Flag(b) => options.has_flag(*b), + FlagOrNv::NameValue(NameValue { name, value }) => { + let value = value.format(&options.generic_args); + options.contains(*name, value) + } + }) + } + + pub(crate) fn parse(input: &MetaItemInner) -> Result { + let span = input.span(); + let pred = Predicate::parse(input)?; + Ok(OnUnimplementedCondition { span, pred }) } +} - pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool { - attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| { - let value = cfg.value.map(|v| { - // `with_no_visible_paths` is also used when generating the options, - // so we need to match it here. - ty::print::with_no_visible_paths!({ - Parser::new(v.as_str(), None, None, false, ParseMode::Format) - .map(|p| match p { - Piece::Lit(s) => s.to_owned(), - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(arg) => { - let s = Symbol::intern(arg); - match options.generic_args.iter().find(|(k, _)| *k == s) { - Some((_, val)) => val.to_string(), - None => format!("{{{arg}}}"), - } - } - Position::ArgumentImplicitlyIs(_) => String::from("{}"), - Position::ArgumentIs(idx) => format!("{{{idx}}}"), - }, - }) - .collect() - }) +/// Predicate(s) in `#[rustc_on_unimplemented]`'s `on` filter. See [`OnUnimplementedCondition`]. +/// +/// It is similar to the predicate in the `cfg` attribute, +/// and may contain nested predicates. +#[derive(Debug)] +enum Predicate { + /// A condition like `on(crate_local)`. + Flag(Flag), + /// A match, like `on(Rhs = "Whatever")`. + Match(NameValue), + /// Negation, like `on(not($pred))`. + Not(Box), + /// True if all predicates are true, like `on(all($a, $b, $c))`. + All(Vec), + /// True if any predicate is true, like `on(any($a, $b, $c))`. + Any(Vec), +} + +impl Predicate { + fn parse(input: &MetaItemInner) -> Result { + let meta_item = match input { + MetaItemInner::MetaItem(meta_item) => meta_item, + MetaItemInner::Lit(lit) => { + return Err(InvalidOnClause::UnsupportedLiteral { span: lit.span }); + } + }; + + let Some(predicate) = meta_item.ident() else { + return Err(InvalidOnClause::ExpectedIdentifier { + span: meta_item.path.span, + path: meta_item.path.clone(), }); + }; - options.contains(cfg.name, &value) - }) + match meta_item.kind { + MetaItemKind::List(ref mis) => match predicate.name { + sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis)?)), + sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis)?)), + sym::not => match &**mis { + [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one)?))), + [first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot { + span: first.span().to(last.span()), + }), + [] => Err(InvalidOnClause::ExpectedOnePredInNot { span: meta_item.span }), + }, + invalid_pred => { + Err(InvalidOnClause::InvalidPredicate { span: predicate.span, invalid_pred }) + } + }, + MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => { + let name = Name::parse(predicate); + let value = FilterFormatString::parse(symbol); + let kv = NameValue { name, value }; + Ok(Predicate::Match(kv)) + } + MetaItemKind::Word => { + let flag = Flag::parse(predicate)?; + Ok(Predicate::Flag(flag)) + } + } + } + + fn parse_sequence(sequence: &[MetaItemInner]) -> Result, InvalidOnClause> { + sequence.iter().map(Predicate::parse).collect() + } + + fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool { + match self { + Predicate::Flag(flag) => eval(FlagOrNv::Flag(flag)), + Predicate::Match(nv) => eval(FlagOrNv::NameValue(nv)), + Predicate::Not(not) => !not.eval(eval), + Predicate::All(preds) => preds.into_iter().all(|pred| pred.eval(eval)), + Predicate::Any(preds) => preds.into_iter().any(|pred| pred.eval(eval)), + } } } -/// Used with `Condition::matches_predicate` to test whether the condition applies +/// Represents a `MetaWord` in an `on`-filter. +#[derive(Debug, Clone, Copy)] +enum Flag { + /// Whether the code causing the trait bound to not be fulfilled + /// is part of the user's crate. + CrateLocal, + /// Whether the obligation is user-specified rather than derived. + Direct, + /// Whether we are in some kind of desugaring like + /// `?` or `try { .. }`. + FromDesugaring, +} + +impl Flag { + fn parse(Ident { name, span }: Ident) -> Result { + match name { + sym::crate_local => Ok(Flag::CrateLocal), + sym::direct => Ok(Flag::Direct), + sym::from_desugaring => Ok(Flag::FromDesugaring), + invalid_flag => Err(InvalidOnClause::InvalidFlag { invalid_flag, span }), + } + } +} + +/// A `MetaNameValueStr` in an `on`-filter. +/// +/// For example, `#[rustc_on_unimplemented(on(name = "value", message = "hello"))]`. +#[derive(Debug, Clone)] +struct NameValue { + name: Name, + /// Something like `"&str"` or `"alloc::string::String"`, + /// in which case it just contains a single string piece. + /// But if it is something like `"&[{A}]"` then it must be formatted later. + value: FilterFormatString, +} + +/// The valid names of the `on` filter. +#[derive(Debug, Clone, Copy)] +enum Name { + Cause, + FromDesugaring, + SelfUpper, + GenericArg(Symbol), +} + +impl Name { + fn parse(Ident { name, .. }: Ident) -> Self { + match name { + sym::_Self | kw::SelfUpper => Name::SelfUpper, + sym::from_desugaring => Name::FromDesugaring, + sym::cause => Name::Cause, + // FIXME(mejrs) Perhaps we should start checking that + // this actually is a valid generic parameter? + generic => Name::GenericArg(generic), + } + } +} + +#[derive(Debug, Clone)] +enum FlagOrNv<'p> { + Flag(&'p Flag), + NameValue(&'p NameValue), +} + +/// Represents a value inside an `on` filter. +/// +/// For example, `#[rustc_on_unimplemented(on(name = "value", message = "hello"))]`. +/// If it is a simple literal like this then `pieces` will be `[LitOrArg::Lit("value")]`. +/// The `Arg` variant is used when it contains formatting like +/// `#[rustc_on_unimplemented(on(Self = "&[{A}]", message = "hello"))]`. +#[derive(Debug, Clone)] +struct FilterFormatString { + pieces: Vec, +} + +#[derive(Debug, Clone)] +enum LitOrArg { + Lit(String), + Arg(String), +} + +impl FilterFormatString { + fn parse(input: Symbol) -> Self { + let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format) + .map(|p| match p { + Piece::Lit(s) => LitOrArg::Lit(s.to_owned()), + // We just ignore formatspecs here + Piece::NextArgument(a) => match a.position { + // In `TypeErrCtxt::on_unimplemented_note` we substitute `"{integral}"` even + // if the integer type has been resolved, to allow targeting all integers. + // `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet, + // from the `Display` impl of `InferTy` to be precise. + // + // Don't try to format these later! + Position::ArgumentNamed(arg @ "integer" | arg @ "integral" | arg @ "float") => { + LitOrArg::Lit(format!("{{{arg}}}")) + } + + // FIXME(mejrs) We should check if these correspond to a generic of the trait. + Position::ArgumentNamed(arg) => LitOrArg::Arg(arg.to_owned()), + + // FIXME(mejrs) These should really be warnings/errors + Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(String::from("{}")), + Position::ArgumentIs(idx) => LitOrArg::Lit(format!("{{{idx}}}")), + }, + }) + .collect(); + Self { pieces } + } + + fn format(&self, generic_args: &[(Symbol, String)]) -> String { + let mut ret = String::new(); + + for piece in &self.pieces { + match piece { + LitOrArg::Lit(s) => ret.push_str(s), + LitOrArg::Arg(arg) => { + let s = Symbol::intern(arg); + match generic_args.iter().find(|(k, _)| *k == s) { + Some((_, val)) => ret.push_str(val), + None => { + // FIXME(mejrs) If we start checking as mentioned in + // FilterFormatString::parse then this shouldn't happen + let _ = std::fmt::write(&mut ret, format_args!("{{{s}}}")); + } + } + } + } + } + + ret + } +} + +/// Used with `OnUnimplementedCondition::matches_predicate` to evaluate the +/// [`OnUnimplementedCondition`]. /// /// For example, given a /// ```rust,ignore (just an example) @@ -85,36 +284,34 @@ impl Condition { /// } /// ``` #[derive(Debug)] -pub struct ConditionOptions { +pub(crate) struct ConditionOptions { /// All the self types that may apply. - /// for example - pub self_types: Vec, + pub(crate) self_types: Vec, // The kind of compiler desugaring. - pub from_desugaring: Option, - /// Match on a variant of [rustc_infer::traits::ObligationCauseCode] - pub cause: Option, - pub crate_local: bool, + pub(crate) from_desugaring: Option, + /// Match on a variant of [rustc_infer::traits::ObligationCauseCode]. + pub(crate) cause: Option, + pub(crate) crate_local: bool, /// Is the obligation "directly" user-specified, rather than derived? - pub direct: bool, - // A list of the generic arguments and their reified types - pub generic_args: Vec<(Symbol, String)>, + pub(crate) direct: bool, + // A list of the generic arguments and their reified types. + pub(crate) generic_args: Vec<(Symbol, String)>, } impl ConditionOptions { - pub fn contains(&self, key: Symbol, value: &Option) -> bool { - match (key, value) { - (sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value), - // from_desugaring as a flag - (sym::from_desugaring, None) => self.from_desugaring.is_some(), - // from_desugaring as key == value - (sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v), - (sym::cause, Some(value)) => self.cause.as_deref() == Some(value), - (sym::crate_local, None) => self.crate_local, - (sym::direct, None) => self.direct, - (other, Some(value)) => { - self.generic_args.iter().any(|(k, v)| *k == other && v == value) - } - _ => false, + fn has_flag(&self, name: Flag) -> bool { + match name { + Flag::CrateLocal => self.crate_local, + Flag::Direct => self.direct, + Flag::FromDesugaring => self.from_desugaring.is_some(), + } + } + fn contains(&self, name: Name, value: String) -> bool { + match name { + Name::SelfUpper => self.self_types.contains(&value), + Name::FromDesugaring => self.from_desugaring.is_some_and(|ds| ds.matches(&value)), + Name::Cause => self.cause == Some(value), + Name::GenericArg(arg) => self.generic_args.contains(&(arg, value)), } } } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 1063115ed237f..04cae1c9b6419 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use rustc_ast::Path; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -31,23 +32,50 @@ pub struct UnableToConstructConstantValue<'a> { } #[derive(Diagnostic)] -#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = E0232)] -pub struct EmptyOnClauseInOnUnimplemented { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = E0232)] -pub struct InvalidOnClauseInOnUnimplemented { - #[primary_span] - #[label] - pub span: Span, +pub enum InvalidOnClause { + #[diag(trait_selection_rustc_on_unimplemented_empty_on_clause, code = E0232)] + Empty { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not, code = E0232)] + ExpectedOnePredInNot { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_unsupported_literal_in_on, code = E0232)] + UnsupportedLiteral { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_expected_identifier, code = E0232)] + ExpectedIdentifier { + #[primary_span] + #[label] + span: Span, + path: Path, + }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_predicate, code = E0232)] + InvalidPredicate { + #[primary_span] + #[label] + span: Span, + invalid_pred: Symbol, + }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_flag, code = E0232)] + InvalidFlag { + #[primary_span] + #[label] + span: Span, + invalid_flag: Symbol, + }, } #[derive(Diagnostic)] -#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = E0232)] +#[diag(trait_selection_rustc_on_unimplemented_missing_value, code = E0232)] #[note] pub struct NoValueInOnUnimplemented { #[primary_span] diff --git a/library/Cargo.lock b/library/Cargo.lock index f5c04a3bf48ce..3df15316d9859 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.156" +version = "0.1.157" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055" +checksum = "74f103f5a97b25e3ed7134dee586e90bbb0496b33ba41816f0e7274e5bb73b50" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 994221de86635..ebfcf8759fa13 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.156", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.157", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 72279e12192bc..a97912304c894 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3666,21 +3666,27 @@ impl Vec { /// Using this method is equivalent to the following code: /// /// ``` - /// # use std::cmp::min; - /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 }; - /// # let mut vec = vec![1, 2, 3, 4, 5, 6]; - /// # let range = 1..4; + /// # let some_predicate = |x: &mut i32| { *x % 2 == 1 }; + /// # let mut vec = vec![0, 1, 2, 3, 4, 5, 6]; + /// # let mut vec2 = vec.clone(); + /// # let range = 1..5; /// let mut i = range.start; - /// while i < min(vec.len(), range.end) { + /// let end_items = vec.len() - range.end; + /// # let mut extracted = vec![]; + /// + /// while i < vec.len() - end_items { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); + /// # extracted.push(val); /// // your code here /// } else { /// i += 1; /// } /// } /// - /// # assert_eq!(vec, vec![1, 4, 5]); + /// # let extracted2: Vec<_> = vec2.extract_if(range, some_predicate).collect(); + /// # assert_eq!(vec, vec2); + /// # assert_eq!(extracted, extracted2); /// ``` /// /// But `extract_if` is easier to use. `extract_if` is also more efficient, diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 72d746289711b..aea6d64281aec 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,6 +1,5 @@ use core::num::NonZero; -use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; @@ -42,31 +41,13 @@ where self.it.next().cloned() } - #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } - #[inline] - fn count(self) -> usize { - self.it.count() - } - - fn last(self) -> Option { - self.it.last().cloned() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).cloned() - } - fn try_fold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -80,58 +61,6 @@ where self.it.map(T::clone).fold(init, f) } - fn find

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.find(move |x| predicate(&x)).cloned() - } - - fn max_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.max_by(move |&x, &y| compare(x, y)).cloned() - } - - fn min_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.min_by(move |&x, &y| compare(x, y)).cloned() - } - - fn cmp(self, other: O) -> Ordering - where - O: IntoIterator, - Self::Item: Ord, - { - self.it.cmp_by(other, |x, y| x.cmp(&y)) - } - - fn partial_cmp(self, other: O) -> Option - where - O: IntoIterator, - Self::Item: PartialOrd, - { - self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) - } - - fn eq(self, other: O) -> bool - where - O: IntoIterator, - Self::Item: PartialEq, - { - self.it.eq_by(other, |x, y| x == &y) - } - - fn is_sorted_by(self, mut compare: F) -> bool - where - F: FnMut(&Self::Item, &Self::Item) -> bool, - { - self.it.is_sorted_by(move |&x, &y| compare(x, y)) - } - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, @@ -152,13 +81,9 @@ where self.it.next_back().cloned() } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) - } - fn try_rfold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -171,13 +96,6 @@ where { self.it.map(T::clone).rfold(init, f) } - - fn rfind

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.rfind(move |x| predicate(&x)).cloned() - } } #[stable(feature = "iter_cloned", since = "1.1.0")] @@ -186,12 +104,10 @@ where I: ExactSizeIterator, T: Clone, { - #[inline] fn len(&self) -> usize { self.it.len() } - #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 73913aa34a9e8..23e4e25ab5388 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,4 +1,3 @@ -use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; @@ -49,35 +48,20 @@ where fn next_chunk( &mut self, - ) -> Result<[Self::Item; N], array::IntoIter> { + ) -> Result<[Self::Item; N], array::IntoIter> + where + Self: Sized, + { >::spec_next_chunk(&mut self.it) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } - #[inline] - fn count(self) -> usize { - self.it.count() - } - - fn last(self) -> Option { - self.it.last().copied() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() - } - fn try_fold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -91,56 +75,21 @@ where self.it.fold(init, copy_fold(f)) } - fn find

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.find(move |x| predicate(&x)).copied() - } - - fn max_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.max_by(move |&x, &y| compare(x, y)).copied() - } - - fn min_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.min_by(move |&x, &y| compare(x, y)).copied() - } - - fn cmp(self, other: O) -> Ordering - where - O: IntoIterator, - Self::Item: Ord, - { - self.it.cmp_by(other, |x, y| x.cmp(&y)) + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() } - fn partial_cmp(self, other: O) -> Option - where - O: IntoIterator, - Self::Item: PartialOrd, - { - self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + fn last(self) -> Option { + self.it.last().copied() } - fn eq(self, other: O) -> bool - where - O: IntoIterator, - Self::Item: PartialEq, - { - self.it.eq_by(other, |x, y| x == &y) + fn count(self) -> usize { + self.it.count() } - fn is_sorted_by(self, mut compare: F) -> bool - where - F: FnMut(&Self::Item, &Self::Item) -> bool, - { - self.it.is_sorted_by(move |&x, &y| compare(x, y)) + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) } unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T @@ -163,13 +112,9 @@ where self.it.next_back().copied() } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) - } - fn try_rfold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -183,11 +128,9 @@ where self.it.rfold(init, copy_fold(f)) } - fn rfind

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.rfind(move |x| predicate(&x)).copied() + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) } } @@ -197,12 +140,10 @@ where I: ExactSizeIterator, T: Copy, { - #[inline] fn len(&self) -> usize { self.it.len() } - #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d7bd28b5279d3..06bec74523bba 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.156" } +compiler_builtins = { version = "=0.1.157" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index f2b978657597a..25de597811027 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -1,64 +1,109 @@ -// ignore-tidy-linelength - +#![crate_type = "lib"] #![feature(rustc_attrs)] - #![allow(unused)] #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"] -trait Foo -{} +trait Foo {} -#[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"] +#[rustc_on_unimplemented = "a collection of type `{Self}` cannot \ + be built from an iterator over elements of type `{A}`"] trait MyFromIterator { /// Builds a container with elements from an external iterator. - fn my_from_iter>(iterator: T) -> Self; + fn my_from_iter>(iterator: T) -> Self; } #[rustc_on_unimplemented] //~^ ERROR malformed `rustc_on_unimplemented` attribute -trait BadAnnotation1 -{} +trait NoContent {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] //~^ ERROR cannot find parameter C on this trait -trait BadAnnotation2 -{} +trait ParameterNotPresent {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] //~^ ERROR positional format arguments are not allowed here -trait BadAnnotation3 -{} +trait NoPositionalArgs {} -#[rustc_on_unimplemented(lorem="")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation4 {} +#[rustc_on_unimplemented(lorem = "")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait EmptyMessage {} #[rustc_on_unimplemented(lorem(ipsum(dolor)))] -//~^ ERROR this attribute must have a valid -trait BadAnnotation5 {} - -#[rustc_on_unimplemented(message="x", message="y")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation6 {} - -#[rustc_on_unimplemented(message="x", on(desugared, message="y"))] -//~^ ERROR this attribute must have a valid -trait BadAnnotation7 {} - -#[rustc_on_unimplemented(on(), message="y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait Invalid {} + +#[rustc_on_unimplemented(message = "x", message = "y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait DuplicateMessage {} + +#[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait OnInWrongPosition {} + +#[rustc_on_unimplemented(on(), message = "y")] //~^ ERROR empty `on`-clause -trait BadAnnotation8 {} - -#[rustc_on_unimplemented(on="x", message="y")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation9 {} - -#[rustc_on_unimplemented(on(x="y"), message="y")] -trait BadAnnotation10 {} - -#[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation11 {} - -pub fn main() { -} +//~^^ NOTE empty `on`-clause here +trait EmptyOn {} + +#[rustc_on_unimplemented(on = "x", message = "y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait ExpectedPredicateInOn {} + +#[rustc_on_unimplemented(on(x = "y"), message = "y")] +trait OnWithoutDirectives {} + +#[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait NestedOn {} + +#[rustc_on_unimplemented(on("y", message = "y"))] +//~^ ERROR literals inside `on`-clauses are not supported +//~^^ NOTE unexpected literal here +trait UnsupportedLiteral {} + +#[rustc_on_unimplemented(on(42, message = "y"))] +//~^ ERROR literals inside `on`-clauses are not supported +//~^^ NOTE unexpected literal here +trait UnsupportedLiteral2 {} + +#[rustc_on_unimplemented(on(not(a, b), message = "y"))] +//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^^ NOTE unexpected quantity of predicates here +trait ExpectedOnePattern {} + +#[rustc_on_unimplemented(on(not(), message = "y"))] +//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^^ NOTE unexpected quantity of predicates here +trait ExpectedOnePattern2 {} + +#[rustc_on_unimplemented(on(thing::What, message = "y"))] +//~^ ERROR expected an identifier inside this `on`-clause +//~^^ NOTE expected an identifier here, not `thing::What` +trait KeyMustBeIdentifier {} + +#[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] +//~^ ERROR expected an identifier inside this `on`-clause +//~^^ NOTE expected an identifier here, not `thing::What` +trait KeyMustBeIdentifier2 {} + +#[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] +//~^ ERROR this predicate is invalid +//~^^ NOTE expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` +trait InvalidPredicate {} + +#[rustc_on_unimplemented(on(something, message = "y"))] +//~^ ERROR invalid flag in `on`-clause +//~^^ NOTE expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` +trait InvalidFlag {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index afd737dc85e69..35b919c7b7853 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -1,5 +1,5 @@ error: malformed `rustc_on_unimplemented` attribute input - --> $DIR/bad-annotation.rs:17:1 + --> $DIR/bad-annotation.rs:15:1 | LL | #[rustc_on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,72 +12,120 @@ LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /* | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0230]: cannot find parameter C on this trait - --> $DIR/bad-annotation.rs:22:90 + --> $DIR/bad-annotation.rs:19:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] | ^ error[E0231]: positional format arguments are not allowed here - --> $DIR/bad-annotation.rs:27:90 + --> $DIR/bad-annotation.rs:23:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] | ^ -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:32:26 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:27:26 | -LL | #[rustc_on_unimplemented(lorem="")] - | ^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(lorem = "")] + | ^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:36:26 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:33:26 | LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] | ^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:40:39 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:39:41 | -LL | #[rustc_on_unimplemented(message="x", message="y")] - | ^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(message = "x", message = "y")] + | ^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:44:39 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:45:41 | -LL | #[rustc_on_unimplemented(message="x", on(desugared, message="y"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]` - --> $DIR/bad-annotation.rs:48:26 + --> $DIR/bad-annotation.rs:51:26 + | +LL | #[rustc_on_unimplemented(on(), message = "y")] + | ^^^^ empty `on`-clause here + +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:56:26 + | +LL | #[rustc_on_unimplemented(on = "x", message = "y")] + | ^^^^^^^^ expected value here + | + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` + +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:65:46 + | +LL | #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here + | + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` + +error[E0232]: literals inside `on`-clauses are not supported + --> $DIR/bad-annotation.rs:71:29 | -LL | #[rustc_on_unimplemented(on(), message="y")] - | ^^^^ empty on-clause here +LL | #[rustc_on_unimplemented(on("y", message = "y"))] + | ^^^ unexpected literal here -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:52:26 +error[E0232]: literals inside `on`-clauses are not supported + --> $DIR/bad-annotation.rs:76:29 | -LL | #[rustc_on_unimplemented(on="x", message="y")] - | ^^^^^^ expected value here +LL | #[rustc_on_unimplemented(on(42, message = "y"))] + | ^^ unexpected literal here + +error[E0232]: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:81:33 | - = note: eg `#[rustc_on_unimplemented(message="foo")]` +LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] + | ^^^^ unexpected quantity of predicates here -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:59:40 +error[E0232]: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:86:29 | -LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(on(not(), message = "y"))] + | ^^^^^ unexpected quantity of predicates here + +error[E0232]: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:91:29 + | +LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` + +error[E0232]: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:96:29 + | +LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` + +error[E0232]: this predicate is invalid + --> $DIR/bad-annotation.rs:101:29 + | +LL | #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] + | ^^^^^^^^^^^^^^ expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` + +error[E0232]: invalid flag in `on`-clause + --> $DIR/bad-annotation.rs:106:29 | - = note: eg `#[rustc_on_unimplemented(message="foo")]` +LL | #[rustc_on_unimplemented(on(something, message = "y"))] + | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` -error: aborting due to 10 previous errors +error: aborting due to 18 previous errors Some errors have detailed explanations: E0230, E0231, E0232. For more information about an error, try `rustc --explain E0230`.