diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a2975935ef553..d48e9fa861a3d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1533,11 +1533,10 @@ impl Expr { // then type of result is trait object. // Otherwise we don't assume the result type. ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => { - if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) { - TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) - } else { + let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) else { return None; - } + }; + TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) } ExprKind::Underscore => TyKind::Infer, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index a5e630a09afe2..c53188a22aedd 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -447,20 +447,17 @@ impl MetaItem { thin_vec![PathSegment::path_root(span)] }; loop { - if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = + let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() - { - segments.push(PathSegment::from_ident(Ident::new(name, span))); - } else { + else { return None; - } - if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - iter.peek() - { - iter.next(); - } else { + }; + segments.push(PathSegment::from_ident(Ident::new(name, span))); + let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek() + else { break; - } + }; + iter.next(); } let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index cbdc89f9deedc..10a8e181c840e 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![doc(test(attr(deny(warnings), allow(internal_features))))] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 0e7db7c9503cb..82bade8829a2f 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -43,13 +43,15 @@ use hir::def::{DefKind, PartialRes, Res}; use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast::*; +use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_errors::ErrorGuaranteed; +use rustc_hir::Target; use rustc_hir::attrs::{AttributeKind, InlineAttr}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; -use rustc_middle::ty::{Asyncness, ResolverAstLowering}; +use rustc_middle::ty::{Asyncness, DelegationFnSigAttrs, ResolverAstLowering}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; @@ -62,6 +64,41 @@ pub(crate) struct DelegationResults<'hir> { pub generics: &'hir hir::Generics<'hir>, } +struct AttributeAdditionInfo { + pub equals: fn(&hir::Attribute) -> bool, + pub kind: AttributeAdditionKind, +} + +enum AttributeAdditionKind { + Default { factory: fn(Span) -> hir::Attribute }, + Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute }, +} + +const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; + +static ATTRIBUTES_ADDITIONS: &[AttributeAdditionInfo] = &[ + AttributeAdditionInfo { + equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })), + kind: AttributeAdditionKind::Inherit { + factory: |span, original_attribute| { + let reason = match original_attribute { + hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason, + _ => None, + }; + + hir::Attribute::Parsed(AttributeKind::MustUse { span, reason }) + }, + flag: DelegationFnSigAttrs::MUST_USE, + }, + }, + AttributeAdditionInfo { + equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))), + kind: AttributeAdditionKind::Default { + factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)), + }, + }, +]; + impl<'hir> LoweringContext<'_, 'hir> { fn is_method(&self, def_id: DefId, span: Span) -> bool { match self.tcx.def_kind(def_id) { @@ -88,7 +125,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); match sig_id { Ok(sig_id) => { - self.add_inline_attribute_if_needed(span); + self.add_attributes_if_needed(span, sig_id); let is_method = self.is_method(sig_id, span); let (param_count, c_variadic) = self.param_count(sig_id); @@ -103,29 +140,100 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn add_inline_attribute_if_needed(&mut self, span: Span) { - const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; - let create_inline_attr_slice = - || [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))]; - - let new_attributes = match self.attrs.get(&PARENT_ID) { - Some(attrs) => { - // Check if reuse already specifies any inline attribute, if so, do nothing - if attrs - .iter() - .any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..)))) + fn add_attributes_if_needed(&mut self, span: Span, sig_id: DefId) { + let new_attributes = self.create_new_attributes( + ATTRIBUTES_ADDITIONS, + span, + sig_id, + self.attrs.get(&PARENT_ID), + ); + + if new_attributes.is_empty() { + return; + } + + let new_arena_allocated_attributes = match self.attrs.get(&PARENT_ID) { + Some(existing_attrs) => self.arena.alloc_from_iter( + existing_attrs.iter().map(|a| a.clone()).chain(new_attributes.into_iter()), + ), + None => self.arena.alloc_from_iter(new_attributes.into_iter()), + }; + + self.attrs.insert(PARENT_ID, new_arena_allocated_attributes); + } + + fn create_new_attributes( + &self, + candidate_additions: &[AttributeAdditionInfo], + span: Span, + sig_id: DefId, + existing_attrs: Option<&&[hir::Attribute]>, + ) -> Vec { + let local_original_attributes = self.parse_local_original_attributes(sig_id); + + candidate_additions + .iter() + .filter_map(|addition_info| { + if let Some(existing_attrs) = existing_attrs + && existing_attrs + .iter() + .any(|existing_attr| (addition_info.equals)(existing_attr)) { - return; + return None; } - self.arena.alloc_from_iter( - attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()), - ) - } - None => self.arena.alloc_from_iter(create_inline_attr_slice()), - }; + match addition_info.kind { + AttributeAdditionKind::Default { factory } => Some(factory(span)), + AttributeAdditionKind::Inherit { flag, factory } => { + let original_attribute = match sig_id.as_local() { + Some(local_id) => self + .resolver + .delegation_fn_sigs + .get(&local_id) + .is_some_and(|sig| sig.attrs_flags.contains(flag)) + .then(|| { + local_original_attributes + .as_ref() + .map(|attrs| { + attrs + .iter() + .find(|base_attr| (addition_info.equals)(base_attr)) + }) + .flatten() + }) + .flatten(), + None => self + .tcx + .get_all_attrs(sig_id) + .iter() + .find(|base_attr| (addition_info.equals)(base_attr)), + }; - self.attrs.insert(PARENT_ID, new_attributes); + original_attribute.map(|a| factory(span, a)) + } + } + }) + .collect::>() + } + + fn parse_local_original_attributes(&self, sig_id: DefId) -> Option> { + if let Some(local_id) = sig_id.as_local() + && let Some(info) = self.resolver.delegation_fn_sigs.get(&local_id) + && !info.to_inherit_attrs.is_empty() + { + Some(AttributeParser::parse_limited_all( + self.tcx.sess, + info.to_inherit_attrs.as_slice(), + None, + Target::Fn, + DUMMY_SP, + DUMMY_NODE_ID, + Some(self.tcx.features()), + ShouldEmit::Nothing, + )) + } else { + None + } } fn get_delegation_sig_id( @@ -220,7 +328,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // We are not forwarding the attributes, as the delegation fn sigs are collected on the ast, // and here we need the hir attributes. let default_safety = - if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod { + if sig.attrs_flags.contains(DelegationFnSigAttrs::TARGET_FEATURE) + || self.tcx.def_kind(parent) == DefKind::ForeignMod + { hir::Safety::Unsafe } else { hir::Safety::Safe diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index f2642838b3c8c..61f816f0baf8f 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,9 +6,6 @@ attr_parsing_bundle_needs_static = attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters -attr_parsing_cfg_predicate_identifier = - `cfg` predicate key must be an identifier - attr_parsing_deprecated_item_suggestion = suggestions on deprecated items are unstable .help = add `#![feature(deprecated_suggestion)]` to the crate root @@ -41,9 +38,6 @@ attr_parsing_empty_link_name = link name must not be empty .label = empty link name -attr_parsing_expected_one_cfg_pattern = - expected 1 cfg-pattern - attr_parsing_expected_single_version_literal = expected single version literal @@ -241,12 +235,6 @@ attr_parsing_unstable_cfg_target_compact = attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` -attr_parsing_unsupported_literal_cfg_boolean = - literal in `cfg` predicate value must be a boolean -attr_parsing_unsupported_literal_cfg_string = - literal in `cfg` predicate value must be a string -attr_parsing_unsupported_literal_generic = - unsupported literal attr_parsing_unsupported_literal_suggestion = consider removing the prefix diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 8c3896975201d..5b4786a64ef2d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -4,7 +4,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token}; use rustc_errors::{Applicability, PResult}; -use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template}; +use rustc_feature::{ + AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template, +}; use rustc_hir::attrs::CfgEntry; use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrPath, RustcVersion}; @@ -23,7 +25,7 @@ use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, }; -use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg}; +use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics}; pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], @@ -410,3 +412,19 @@ fn parse_cfg_attr_internal<'a>( Ok((cfg_predicate, expanded_attrs)) } + +fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { + let gate = find_gated_cfg(|sym| sym == name); + if let (Some(feats), Some(gated_cfg)) = (features, gate) { + gate_cfg(gated_cfg, span, sess, feats); + } +} + +#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable +fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { + let (cfg, feature, has_feature) = gated_cfg; + if !has_feature(features) && !cfg_span.allows_unstable(*feature) { + let explain = format!("`cfg({cfg})` is experimental and subject to change"); + feature_err(sess, *feature, cfg_span, explain).emit(); + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs deleted file mode 100644 index acb234480d5dd..0000000000000 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ /dev/null @@ -1,210 +0,0 @@ -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_feature::{Features, GatedCfg, find_gated_cfg}; -use rustc_hir::RustcVersion; -use rustc_session::Session; -use rustc_session::lint::{BuiltinLintDiag, Lint}; -use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; - -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; -use crate::{fluent_generated, parse_version}; - -/// Emitter of a builtin lint from `cfg_matches`. -/// -/// Used to support emitting a lint (currently on check-cfg), either: -/// - as an early buffered lint (in `rustc`) -/// - or has a "normal" lint from HIR (in `rustdoc`) -pub trait CfgMatchesLintEmitter { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag); -} - -impl CfgMatchesLintEmitter for NodeId { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) { - sess.psess.buffer_lint(lint, sp, *self, diag); - } -} - -#[derive(Clone, Debug)] -pub struct Condition { - pub name: Symbol, - pub name_span: Span, - pub value: Option, - pub value_span: Option, - pub span: Span, -} - -pub fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| sym == name); - if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(gated_cfg, span, sess, feats); - } -} - -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { - let (cfg, feature, has_feature) = gated_cfg; - if !has_feature(features) && !cfg_span.allows_unstable(*feature) { - let explain = format!("`cfg({cfg})` is experimental and subject to change"); - feature_err(sess, *feature, cfg_span, explain).emit(); - } -} - -/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to -/// evaluate individual items. -pub fn eval_condition( - cfg: &MetaItemInner, - sess: &Session, - features: Option<&Features>, - eval: &mut impl FnMut(Condition) -> bool, -) -> bool { - let dcx = sess.dcx(); - - let cfg = match cfg { - MetaItemInner::MetaItem(meta_item) => meta_item, - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - return *b; - } - _ => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: cfg.span(), - reason: UnsupportedLiteralReason::CfgBoolean, - is_bytestr: false, - start_point_span: sess.source_map().start_point(cfg.span()), - }); - return false; - } - }; - - match &cfg.kind { - MetaItemKind::List(mis) if cfg.has_name(sym::version) => { - try_gate_cfg(sym::version, cfg.span, sess, features); - let (min_version, span) = match &mis[..] { - [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { - (sym, span) - } - [ - MetaItemInner::Lit(MetaItemLit { span, .. }) - | MetaItemInner::MetaItem(MetaItem { span, .. }), - ] => { - dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); - return false; - } - [..] => { - dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { - span: cfg.span, - }); - return false; - } - }; - let Some(min_version) = parse_version(*min_version) else { - dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span }); - return false; - }; - - // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details - if sess.psess.assume_incomplete_release { - RustcVersion::current_overridable() > min_version - } else { - RustcVersion::current_overridable() >= min_version - } - } - MetaItemKind::List(mis) => { - for mi in mis.iter() { - if mi.meta_item_or_bool().is_none() { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: mi.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: sess.source_map().start_point(mi.span()), - }); - return false; - } - } - - // The unwraps below may look dangerous, but we've already asserted - // that they won't fail with the loop above. - match cfg.name() { - Some(sym::any) => mis - .iter() - // We don't use any() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), - Some(sym::all) => mis - .iter() - // We don't use all() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), - Some(sym::not) => { - let [mi] = mis.as_slice() else { - dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); - return false; - }; - - !eval_condition(mi, sess, features, eval) - } - Some(sym::target) => { - if let Some(features) = features - && !features.cfg_target_compact() - { - feature_err( - sess, - sym::cfg_target_compact, - cfg.span, - fluent_generated::attr_parsing_unstable_cfg_target_compact, - ) - .emit(); - } - - mis.iter().fold(true, |res, mi| { - let Some(mut mi) = mi.meta_item().cloned() else { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { - span: mi.span(), - }); - return false; - }; - - if let [seg, ..] = &mut mi.path.segments[..] { - seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); - } - - res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval) - }) - } - _ => { - dcx.emit_err(session_diagnostics::InvalidPredicate { - span: cfg.span, - predicate: pprust::path_to_string(&cfg.path), - }); - false - } - } - } - MetaItemKind::Word | MetaItemKind::NameValue(..) - if cfg.path.segments.len() != 1 - || cfg.path.segments[0].ident.is_path_segment_keyword() => - { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); - true - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::CfgString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: sess.source_map().start_point(lit.span), - }); - true - } - MetaItemKind::Word | MetaItemKind::NameValue(..) => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - eval(Condition { - name: ident.name, - name_span: ident.span, - value: cfg.value_str(), - value_span: cfg.name_value_literal_span(), - span: cfg.span, - }) - } - } -} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index bd58c44214a23..64f29a4729c3d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -32,7 +32,6 @@ mod prelude; pub(crate) mod allow_unstable; pub(crate) mod body; pub(crate) mod cfg; -pub(crate) mod cfg_old; pub(crate) mod cfg_select; pub(crate) mod codegen_attrs; pub(crate) mod confusables; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b3ebb0f4fec1a..571cb884c1fcd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,7 +8,7 @@ use rustc_hir::{ use super::prelude::*; use super::util::parse_version; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; +use crate::session_diagnostics::{self}; macro_rules! reject_outside_std { ($cx: ident) => { @@ -302,12 +302,7 @@ pub(crate) fn parse_stability( for param in list.mixed() { let param_span = param.span(); let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param_span, - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param_span), - }); + cx.unexpected_literal(param.span()); return None; }; @@ -382,12 +377,7 @@ pub(crate) fn parse_unstability( for param in list.mixed() { let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param.span()), - }); + cx.unexpected_literal(param.span()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index cb02bb9d501fc..411b4dd75e661 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -107,7 +107,6 @@ pub mod validate_attr; pub use attributes::cfg::{ CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry, }; -pub use attributes::cfg_old::*; pub use attributes::cfg_select::*; pub use attributes::util::{is_builtin_attr, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2bbdb5c2590bf..b50a7f92fcdc5 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -12,19 +12,6 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; -pub(crate) enum UnsupportedLiteralReason { - Generic, - CfgString, - CfgBoolean, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)] -pub(crate) struct ExpectedOneCfgPattern { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_predicate, code = E0537)] pub(crate) struct InvalidPredicate { @@ -230,46 +217,6 @@ pub(crate) struct InvalidReprHintNoValue { pub name: Symbol, } -/// Error code: E0565 -// FIXME(jdonszelmann): slowly phased out -pub(crate) struct UnsupportedLiteral { - pub span: Span, - pub reason: UnsupportedLiteralReason, - pub is_bytestr: bool, - pub start_point_span: Span, -} - -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new( - dcx, - level, - match self.reason { - UnsupportedLiteralReason::Generic => { - fluent::attr_parsing_unsupported_literal_generic - } - UnsupportedLiteralReason::CfgString => { - fluent::attr_parsing_unsupported_literal_cfg_string - } - UnsupportedLiteralReason::CfgBoolean => { - fluent::attr_parsing_unsupported_literal_cfg_boolean - } - }, - ); - diag.span(self.span); - diag.code(E0565); - if self.is_bytestr { - diag.span_suggestion( - self.start_point_span, - fluent::attr_parsing_unsupported_literal_suggestion, - "", - Applicability::MaybeIncorrect, - ); - } - diag - } -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)] pub(crate) struct InvalidReprAlignNeedArg { @@ -375,13 +322,6 @@ pub(crate) struct RustcAllowedUnstablePairing { pub span: Span, } -#[derive(Diagnostic)] -#[diag(attr_parsing_cfg_predicate_identifier)] -pub(crate) struct CfgPredicateIdentifier { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_deprecated_item_suggestion)] pub(crate) struct DeprecatedItemSuggestion { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2999d1f2926cc..5cfe9db009bff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -561,11 +561,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { VarDebugInfoContents::Place(ref p) => p == place, _ => false, }); - let arg_name = if let Some(var_info) = var_info { - var_info.name - } else { - return; - }; + let Some(var_info) = var_info else { return }; + let arg_name = var_info.name; struct MatchArgFinder { expr_span: Span, match_arg_span: Option, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index bfdfa896cd2b9..8e18bf5577584 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -850,16 +850,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { // will only ever have one item at any given time, but by using a vector, we can pop from // it which simplifies the termination logic. let mut queue = vec![location]; - let mut target = - if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt { - if let Some(local) = place.as_local() { - local - } else { - return false; - } - } else { - return false; - }; + let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt else { + return false; + }; + let Some(mut target) = place.as_local() else { return false }; debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); while let Some(current_location) = queue.pop() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index e13c1c712d8d7..e725b13434a1f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1124,16 +1124,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { use self::UseSpans::*; debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); - let target = match self.body[location.block].statements.get(location.statement_index) { - Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => { - if let Some(local) = place.as_local() { - local - } else { - return OtherUse(use_span); - } - } - _ => return OtherUse(use_span), + let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = + self.body[location.block].statements.get(location.statement_index) + else { + return OtherUse(use_span); }; + let Some(target) = place.as_local() else { return OtherUse(use_span) }; if self.body.local_kind(target) != LocalKind::Temp { // operands are always temporaries. diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7d72de7efa4a1..e9039d4311b66 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -142,12 +142,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } else { item_msg = access_place_desc; let local_info = self.body.local_decls[local].local_info(); - if let LocalInfo::StaticRef { def_id, .. } = *local_info { - let static_name = &self.infcx.tcx.item_name(def_id); - reason = format!(", as `{static_name}` is an immutable static item"); - } else { + let LocalInfo::StaticRef { def_id, .. } = *local_info else { bug!("is_ref_to_static return true, but not ref to static?"); - } + }; + let static_name = &self.infcx.tcx.item_name(def_id); + reason = format!(", as `{static_name}` is an immutable static item"); } } PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index f4bbdabf7f216..9c2b9139367a9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -847,11 +847,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.scope); - let param = if let Some(param) = + let Some(param) = find_param_with_region(self.infcx.tcx, self.mir_def_id(), f, outlived_f) - { - param - } else { + else { return; }; @@ -930,37 +928,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let tcx = self.infcx.tcx; - let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category { - let (fn_did, args) = match func_ty.kind() { - ty::FnDef(fn_did, args) => (fn_did, args), - _ => return, - }; - debug!(?fn_did, ?args); + let ConstraintCategory::CallArgument(Some(func_ty)) = category else { return }; + let ty::FnDef(fn_did, args) = func_ty.kind() else { return }; + debug!(?fn_did, ?args); - // Only suggest this on function calls, not closures - let ty = tcx.type_of(fn_did).instantiate_identity(); - debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); - if let ty::Closure(_, _) = ty.kind() { - return; - } - - if let Ok(Some(instance)) = ty::Instance::try_resolve( - tcx, - self.infcx.typing_env(self.infcx.param_env), - *fn_did, - self.infcx.resolve_vars_if_possible(args), - ) { - instance - } else { - return; - } - } else { + // Only suggest this on function calls, not closures + let ty = tcx.type_of(fn_did).instantiate_identity(); + debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); + if let ty::Closure(_, _) = ty.kind() { + return; + } + let Ok(Some(instance)) = ty::Instance::try_resolve( + tcx, + self.infcx.typing_env(self.infcx.param_env), + *fn_did, + self.infcx.resolve_vars_if_possible(args), + ) else { return; }; - let param = match find_param_with_region(tcx, self.mir_def_id(), f, o) { - Some(param) => param, - None => return, + let Some(param) = find_param_with_region(tcx, self.mir_def_id(), f, o) else { + return; }; debug!(?param); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8d61ffde116c5..d82357fca2d45 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,6 +2,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] diff --git a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs index edd7ca578b727..dc174775af2e5 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs @@ -67,12 +67,11 @@ impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> { match context { PlaceContext::NonMutatingUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { - let path = match self.move_data.rev_lookup.find(place.as_ref()) { - LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path, - _ => { - // There's no path access to emit. - return; - } + let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) = + self.move_data.rev_lookup.find(place.as_ref()) + else { + // There's no path access to emit. + return; }; debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})"); self.facts.path_accessed_at_base.push((path, self.location_to_index(location))); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index ecaf88a26259e..33ffe4cc4e9c8 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -130,11 +130,9 @@ impl UnwindContext { return; } - let unwind_info = if let Some(unwind_info) = + let Some(unwind_info) = context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap() - { - unwind_info - } else { + else { return; }; diff --git a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs index c93fe93521033..f38c1f96e6ed5 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs @@ -29,11 +29,7 @@ pub(crate) fn maybe_known_branch_taken( arg: Value, test_zero: bool, ) -> Option { - let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { - arg_inst - } else { - return None; - }; + let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) else { return None }; match bcx.func.dfg.insts[arg_inst] { InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 23d16eda030c1..a38dcf8e4c93b 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -460,9 +460,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::bitreverse => self.bit_reverse(width, args[0].immediate()), sym::rotate_left | sym::rotate_right => { - // TODO(antoyo): implement using algorithm from: + // Using optimized branchless algorithm from: // https://blog.regehr.org/archives/1063 - // for other platforms. + // This implementation uses the pattern (x<>(-n&(width-1))) + // which generates efficient code for other platforms. let is_left = name == sym::rotate_left; let val = args[0].immediate(); let raw_shift = args[1].immediate(); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index c7ed887b30d02..39b4bb3ebefab 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -774,24 +774,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Err(()); }}; } - let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 16 => ("", elem_ty, Some(bx.cx.double_type)), - 32 => ("f", elem_ty, None), - 64 => ("", elem_ty, None), - _ => { - return_error!(InvalidMonomorphization::FloatingPointVector { - span, - name, - f_ty: *f, - in_ty - }); - } - } - } else { + let ty::Float(ref f) = *in_elem.kind() else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; + let elem_ty = bx.cx.type_float_from_ty(*f); + let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() { + 16 => ("", elem_ty, Some(bx.cx.double_type)), + 32 => ("f", elem_ty, None), + 64 => ("", elem_ty, None), + _ => { + return_error!(InvalidMonomorphization::FloatingPointVector { + span, + name, + f_ty: *f, + in_ty + }); + } + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 33541f7b695f8..e43bd8c2feef5 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1756,11 +1756,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }}; } - let elem_ty = if let ty::Float(f) = in_elem.kind() { - bx.cx.type_float_from_ty(*f) - } else { + let ty::Float(f) = in_elem.kind() else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; + let elem_ty = bx.cx.type_float_from_ty(*f); let vec_ty = bx.type_vector(elem_ty, in_len); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 0ab0cb0ef88a5..bfbe7bc20052e 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -721,11 +721,10 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { }; // First read the ret symbol from the attribute - let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity { - p1.segments.first().unwrap().ident - } else { + let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity else { span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity"); }; + let ret_symbol = p1.segments.first().unwrap().ident; // Then parse it into an actual DiffActivity let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else { diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 2fce4b8c0566e..6c74ed2a5121d 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] +#![deny(clippy::manual_let_else)] #![feature(array_try_map)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 0ef3bb319ff80..72d5f004194a8 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -75,6 +75,7 @@ impl_dyn_send!( [std::sync::Mutex where T: ?Sized+ DynSend] [std::sync::mpsc::Sender where T: DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::Weak where T: ?Sized + DynSync + DynSend] [std::sync::LazyLock where T: DynSend, F: DynSend] [std::collections::HashSet where K: DynSend, S: DynSend] [std::collections::HashMap where K: DynSend, V: DynSend, S: DynSend] @@ -157,6 +158,7 @@ impl_dyn_sync!( [std::sync::OnceLock where T: DynSend + DynSync] [std::sync::Mutex where T: ?Sized + DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::Weak where T: ?Sized + DynSync + DynSend] [std::sync::LazyLock where T: DynSend + DynSync, F: DynSend] [std::collections::HashSet where K: DynSync, S: DynSync] [std::collections::HashMap where K: DynSync, V: DynSync, S: DynSync] diff --git a/compiler/rustc_error_codes/src/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md index c1f43fa741cfa..7603be4fcc935 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0536.md +++ b/compiler/rustc_error_codes/src/error_codes/E0536.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + The `not` cfg-predicate was malformed. Erroneous code example (using `cargo doc`): diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index c548cea537f40..8d2cc23f97639 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -788,11 +788,10 @@ pub fn compile_declarative_macro( let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. - let lhs = if let mbe::TokenTree::Delimited(.., delimited) = lhs_tt { - mbe::macro_parser::compute_locs(&delimited.tts) - } else { + let mbe::TokenTree::Delimited(.., delimited) = lhs_tt else { return dummy_syn_ext(guar.unwrap()); }; + let lhs = mbe::macro_parser::compute_locs(&delimited.tts); if let Some(args) = args { let args_span = args.span(); let mbe::TokenTree::Delimited(.., delimited) = args else { diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 7a5776f0d5a93..c27954b6d14e4 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,6 +4,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![deny(clippy::manual_let_else)] #![feature(associated_type_defaults)] #![feature(closure_track_caller)] #![feature(const_default)] diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3cfcac5c72915..2e06684e0c7a8 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1551,15 +1551,15 @@ fn const_param_default<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - let default_ct = match tcx.hir_node_by_def_id(def_id) { - hir::Node::GenericParam(hir::GenericParam { - kind: hir::GenericParamKind::Const { default: Some(ct), .. }, - .. - }) => ct, - _ => span_bug!( + let hir::Node::GenericParam(hir::GenericParam { + kind: hir::GenericParamKind::Const { default: Some(default_ct), .. }, + .. + }) = tcx.hir_node_by_def_id(def_id) + else { + span_bug!( tcx.def_span(def_id), "`const_param_default` expected a generic parameter with a constant" - ), + ) }; let icx = ItemCtxt::new(tcx, def_id); let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 6b51e31579616..7025f7ac84b02 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -188,29 +188,26 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { let existing = match var.kind() { ty::GenericArgKind::Lifetime(re) => { - if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = re.kind() - { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } ty::GenericArgKind::Type(ty) => { - if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = ct.kind() - { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } }; diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 30324da3c6516..d835a7bbb8d29 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -763,9 +763,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { &self, err: &mut Diag<'_, impl EmissionGuarantee>, ) { - let trait_ = match self.tcx.trait_of_assoc(self.def_id) { - Some(def_id) => def_id, - None => return, + let Some(trait_) = self.tcx.trait_of_assoc(self.def_id) else { + return; }; // Skip suggestion when the associated function is itself generic, it is unclear @@ -1077,15 +1076,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// Builds the `type defined here` message. fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { - let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { - if self.tcx.sess.source_map().is_span_accessible(def_span) { - def_span.into() - } else { - return; - } - } else { + let Some(def_span) = self.tcx.def_ident_span(self.def_id) else { return }; + if !self.tcx.sess.source_map().is_span_accessible(def_span) { return; }; + let mut spans: MultiSpan = def_span.into(); let msg = { let def_kind = self.tcx.def_descr(self.def_id); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 600684d4f5147..5fc201db68e5d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1749,10 +1749,8 @@ fn generics_args_err_extend<'a>( GenericsArgsErrExtend::SelfTyAlias { def_id, span } => { let ty = tcx.at(span).type_of(def_id).instantiate_identity(); let span_of_impl = tcx.span_of_impl(def_id); - let def_id = match *ty.kind() { - ty::Adt(self_def, _) => self_def.did(), - _ => return, - }; + let ty::Adt(self_def, _) = *ty.kind() else { return }; + let def_id = self_def.did(); let type_name = tcx.item_name(def_id); let span_of_ty = tcx.def_ident_span(def_id); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 538fb8c7df1ea..79c5fbab1ffa2 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,6 +59,7 @@ This API is completely unstable and subject to change. #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(gen_blocks)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f59fcab46661f..714c6a104a9e1 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -458,15 +458,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... - if let hir::Node::Expr(&hir::Expr { + let hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. }) = self.tcx.parent_hir_node(parent_hir_id) - { - fn_decl_span - } else { + else { return; - } + }; + fn_decl_span } else { return; }; diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f1e74028f4ce7..3f214b4d2fccb 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -415,11 +415,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); Some(self.resolve_vars_if_possible(possible_rcvr_ty)) }); - if let Some(rcvr_ty) = possible_rcvr_ty { - rcvr_ty - } else { - return false; - } + let Some(rcvr_ty) = possible_rcvr_ty else { return false }; + rcvr_ty } }; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a31c2bbb8d6b2..48082560bb83b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3180,6 +3180,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(within_macro_span, "due to this macro variable"); } + // Check if there is an associated function with the same name. + if let Some(def_id) = base_ty.peel_refs().ty_adt_def().map(|d| d.did()) { + for impl_def_id in self.tcx.inherent_impls(def_id) { + for item in self.tcx.associated_items(impl_def_id).in_definition_order() { + if let ExprKind::Field(base_expr, _) = expr.kind + && item.name() == field.name + && matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. }) + { + err.span_label(field.span, "this is an associated function, not a method"); + err.note("found the following associated function; to be used as method, it must have a `self` parameter"); + let impl_ty = self.tcx.type_of(impl_def_id).instantiate_identity(); + err.span_note( + self.tcx.def_span(item.def_id), + format!("the candidate is defined in an impl for the type `{impl_ty}`"), + ); + + let ty_str = match base_ty.peel_refs().kind() { + ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args), + _ => base_ty.peel_refs().to_string(), + }; + err.multipart_suggestion( + "use associated function syntax instead", + vec![ + (base_expr.span, ty_str), + (base_expr.span.between(field.span), "::".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return err; + } + } + } + } + // try to add a suggestion in case the field is a nested field of a field of the Adt let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind() diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 561230c193ce2..27b66d07f98e4 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1561,19 +1561,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx base_place: PlaceWithHirId<'tcx>, ) -> Result, Cx::Error> { let base_curr_ty = base_place.place.ty(); - let deref_ty = match self + let Some(deref_ty) = self .cx .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) .builtin_deref(true) - { - Some(ty) => ty, - None => { - debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); - return Err(self.cx.report_bug( - self.cx.tcx().hir_span(node), - "explicit deref of non-derefable type", - )); - } + else { + debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); + return Err(self + .cx + .report_bug(self.cx.tcx().hir_span(node), "explicit deref of non-derefable type")); }; let mut projections = base_place.place.projections; projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 854202c312705..5c04f2b5f63c4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -48,33 +48,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let uninstantiated_pred = match flavor { - ClauseFlavor::Where => { + ClauseFlavor::Where if let Some(pred) = self .tcx .predicates_of(def_id) .instantiate_identity(self.tcx) .predicates .into_iter() - .nth(idx) - { - pred - } else { - return false; - } + .nth(idx) => + { + pred } - ClauseFlavor::Const => { + ClauseFlavor::Const if let Some((pred, _)) = self .tcx .const_conditions(def_id) .instantiate_identity(self.tcx) .into_iter() - .nth(idx) - { - pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe) - } else { - return false; - } + .nth(idx) => + { + pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe) } + _ => return false, }; let generics = self.tcx.generics_of(def_id); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 57da450d832cd..d04133ccee976 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1467,11 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, } }); - if let Some(new_def_id) = new_def_id { - def_id = new_def_id; - } else { - return; - } + let Some(new_def_id) = new_def_id else { return }; + def_id = new_def_id; } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1adcd91cc3ee2..d51b052e0d1bc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1795,7 +1795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ty), hir::Path { segments: [segment], .. }, )) - | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => { + | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id) && let Ok(pick) = self.probe_for_name( Mode::Path, @@ -1805,12 +1805,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, expr.hir_id, ProbeScope::TraitsInScope, - ) - { - (pick.item, segment) - } else { - return false; - } + ) => + { + (pick.item, segment) } hir::ExprKind::Path(QPath::Resolved( None, @@ -1821,16 +1818,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if old_item_name != segment.ident.name { return false; } - if let Some(item) = self + let Some(item) = self .tcx .associated_items(self.tcx.parent(old_def_id)) .filter_by_name_unhygienic(capitalized_name) .next() - { - (*item, segment) - } else { + else { return false; - } + }; + (*item, segment) } _ => return false, }; diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 6460bd72c7973..6626c3edb5466 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -121,13 +121,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { len, ) }; - if let Some(len) = len.try_to_target_usize(self.tcx()) { - (len, ty) - } else { + let Some(len) = len.try_to_target_usize(self.tcx()) else { return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength( field.did, len, )); - } + }; + (len, ty) } _ => (fields.len() as u64, elem_ty), }; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d3ef1d63e8ba9..9ca5ddd494aeb 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4b9ad345210dd..18bc00d653516 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2511,7 +2511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { applicability = Applicability::HasPlaceholders; "(...)".to_owned() }; - err.span_suggestion( + err.span_suggestion_verbose( sugg_span, "use associated function syntax instead", format!("{ty_str}::{item_name}{args}"), @@ -3543,10 +3543,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, return_type: Option>, ) { - let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(output_ty), - _ => return, - }; + let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { return }; + let output_ty = self.resolve_vars_if_possible(output_ty); let method_exists = self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type); debug!("suggest_await_before_method: is_method_exist={}", method_exists); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 87b208923ddb9..810760e9f53e6 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1072,11 +1072,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, ) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - let def = if let hir::ExprKind::Path(ref qpath) = expr.kind { - cx.qpath_res(qpath, expr.hir_id) - } else { - return None; - }; + let hir::ExprKind::Path(ref qpath) = expr.kind else { return None }; + let def = cx.qpath_res(qpath, expr.hir_id); if let Res::Def(DefKind::Fn, did) = def { if !def_id_is_transmute(cx, did) { return None; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4e7a3e4051767..49929a0a9bc76 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -22,6 +22,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs index f20605c914951..9220702c21f1d 100644 --- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs +++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs @@ -120,10 +120,8 @@ impl Expr2024 { fn check_ident_token(&mut self, cx: &crate::EarlyContext<'_>, token: &Token) { debug!("check_ident_token: {:?}", token); - let (sym, edition) = match token.kind { - TokenKind::Ident(sym, _) => (sym, Edition::Edition2024), - _ => return, - }; + let TokenKind::Ident(sym, _) = token.kind else { return }; + let edition = Edition::Edition2024; debug!("token.span.edition(): {:?}", token.span.edition()); if token.span.edition() >= edition { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index baecc14424ecf..99cce0c44b86d 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -48,6 +48,7 @@ declare_lint_pass! { ILL_FORMED_ATTRIBUTE_INPUT, INCOMPLETE_INCLUDE, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, INLINE_NO_SANITIZE, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5f62d44df6b61..ee3e89e57bd42 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,6 +30,7 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![feature(allocator_api)] #![feature(assert_matches)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 2e64fc290fcc2..279c34cb275d9 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -706,12 +706,9 @@ impl<'tcx> FallibleTypeFolder> for MakeSuggestableFolder<'tcx> { | Bound(_, _) | Placeholder(_) | Error(_) => { - if let Some(placeholder) = self.placeholder { - // We replace these with infer (which is passed in from an infcx). - placeholder - } else { - return Err(()); - } + let Some(placeholder) = self.placeholder else { return Err(()) }; + // We replace these with infer (which is passed in from an infcx). + placeholder } Alias(Opaque, AliasTy { def_id, .. }) => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ca4949910f27..b91176e3d4862 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -25,6 +25,7 @@ pub use generic_args::{GenericArgKind, TermKind, *}; pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; +use rustc_ast::AttrVec; use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; @@ -221,13 +222,24 @@ pub struct ResolverAstLowering { pub delegation_fn_sigs: LocalDefIdMap, } +bitflags::bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub struct DelegationFnSigAttrs: u8 { + const TARGET_FEATURE = 1 << 0; + const MUST_USE = 1 << 1; + } +} + +pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE; + #[derive(Debug)] pub struct DelegationFnSig { pub header: ast::FnHeader, pub param_count: usize, pub has_self: bool, pub c_variadic: bool, - pub target_feature: bool, + pub attrs_flags: DelegationFnSigAttrs, + pub to_inherit_attrs: AttrVec, } #[derive(Clone, Copy, Debug, HashStable)] @@ -2395,9 +2407,7 @@ fn typetree_from_ty_impl_inner<'tcx>( } if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { - let inner_ty = if let Some(inner) = ty.builtin_deref(true) { - inner - } else { + let Some(inner_ty) = ty.builtin_deref(true) else { return TypeTree::new(); }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 72573d96dc54f..852a0017687f2 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1528,18 +1528,13 @@ impl<'tcx> Ty<'tcx> { let mut cor_ty = self; let mut ty = cor_ty; loop { - if let ty::Coroutine(def_id, args) = ty.kind() { - cor_ty = ty; - f(ty); - if tcx.is_async_drop_in_place_coroutine(*def_id) { - ty = args.first().unwrap().expect_ty(); - continue; - } else { - return cor_ty; - } - } else { + let ty::Coroutine(def_id, args) = ty.kind() else { return cor_ty }; + cor_ty = ty; + f(ty); + if !tcx.is_async_drop_in_place_coroutine(*def_id) { return cor_ty; } + ty = args.first().unwrap().expect_ty(); } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 6faef3e974a05..800d4e406cf09 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -100,11 +100,8 @@ impl<'tcx> MovePath<'tcx> { move_paths: &IndexSlice>, f: impl Fn(MovePathIndex) -> bool, ) -> Option { - let mut todo = if let Some(child) = self.first_child { - vec![child] - } else { - return None; - }; + let Some(child) = self.first_child else { return None }; + let mut todo = vec![child]; while let Some(mpi) = todo.pop() { if f(mpi) { @@ -331,11 +328,10 @@ impl<'tcx> MovePathLookup<'tcx> { MoveSubPathResult::Stop => None, }; - if let Some(&subpath) = subpath { - result = subpath; - } else { + let Some(&subpath) = subpath else { return LookupResult::Parent(Some(result)); - } + }; + result = subpath; } LookupResult::Exact(result) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index b1ff7ffc60edd..daf304c1bf9df 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -721,11 +721,8 @@ impl<'tcx> Map<'tcx> { // Enum variant fields and enum discriminants alias each another. self.for_each_variant_sibling(index, sub, f); } - if let Some(sub) = sub { - index = sub - } else { - return; - } + let Some(sub) = sub else { return }; + index = sub; } self.for_each_value_inside(index, f); } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ebfeba5ad2252..92c74e7fc2763 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -590,31 +590,30 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { let fields = fields.iter().map(|&f| self.eval_to_const(f)).collect::>>()?; let variant = if ty.ty.is_enum() { Some(variant) } else { None }; - if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) - { - let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; - let variant_dest = if let Some(variant) = variant { - self.ecx.project_downcast(&dest, variant).discard_err()? - } else { - dest.clone() - }; - for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = self - .ecx - .project_field(&variant_dest, FieldIdx::from_usize(field_index)) - .discard_err()?; - self.ecx.copy_op(op, &field_dest).discard_err()?; - } - self.ecx - .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) - .discard_err()?; - self.ecx - .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .discard_err()?; - dest.into() - } else { + let (BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) = ty.backend_repr + else { return None; + }; + let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; + let variant_dest = if let Some(variant) = variant { + self.ecx.project_downcast(&dest, variant).discard_err()? + } else { + dest.clone() + }; + for (field_index, op) in fields.into_iter().enumerate() { + let field_dest = self + .ecx + .project_field(&variant_dest, FieldIdx::from_usize(field_index)) + .discard_err()?; + self.ecx.copy_op(op, &field_dest).discard_err()?; } + self.ecx + .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) + .discard_err()?; + self.ecx + .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) + .discard_err()?; + dest.into() } Union(active_field, field) => { let field = self.eval_to_const(field)?; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 6b0c331ff5415..7d631e96c32a7 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -410,14 +410,8 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_to_target_usize(self.tcx) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } + let ty::Array(_, len) = ty.kind() else { return Err(Unpromotable) }; + let Some(0) = len.try_to_target_usize(self.tcx) else { return Err(Unpromotable) }; } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c65e0bb25897c..70c28421c57ea 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -445,17 +445,15 @@ where goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { let cx = ecx.cx(); - let tupled_inputs_and_output = - match structural_traits::extract_tupled_inputs_and_output_from_callable( + let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( cx, goal.predicate.self_ty(), goal_kind, - )? { - Some(tupled_inputs_and_output) => tupled_inputs_and_output, - None => { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - }; + )? + else { + return ecx.forced_ambiguity(MaybeCause::Ambiguity); + }; let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 168921655a394..651f073efb828 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -360,17 +360,15 @@ where } let cx = ecx.cx(); - let tupled_inputs_and_output = - match structural_traits::extract_tupled_inputs_and_output_from_callable( + let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( cx, goal.predicate.self_ty(), goal_kind, - )? { - Some(a) => a, - None => { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - }; + )? + else { + return ecx.forced_ambiguity(MaybeCause::Ambiguity); + }; let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. @@ -1409,42 +1407,39 @@ where let where_bounds: Vec<_> = candidates .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - if let Some((response, info)) = self.try_merge_candidates(&where_bounds) { - match info { - // If there's an always applicable candidate, the result of all - // other candidates does not matter. This means we can ignore - // them when checking whether we've reached a fixpoint. - // - // We always prefer the first always applicable candidate, even if a - // later candidate is also always applicable and would result in fewer - // reruns. We could slightly improve this by e.g. searching for another - // always applicable candidate which doesn't depend on any cycle heads. - // - // NOTE: This is optimization is observable in case there is an always - // applicable global candidate and another non-global candidate which only - // applies because of a provisional result. I can't even think of a test - // case where this would occur and even then, this would not be unsound. - // Supporting this makes the code more involved, so I am just going to - // ignore this for now. - MergeCandidateInfo::AlwaysApplicable(i) => { - for (j, c) in where_bounds.into_iter().enumerate() { - if i != j { - self.ignore_candidate_head_usages(c.head_usages) - } + let Some((response, info)) = self.try_merge_candidates(&where_bounds) else { + return Ok((self.bail_with_ambiguity(&where_bounds), None)); + }; + match info { + // If there's an always applicable candidate, the result of all + // other candidates does not matter. This means we can ignore + // them when checking whether we've reached a fixpoint. + // + // We always prefer the first always applicable candidate, even if a + // later candidate is also always applicable and would result in fewer + // reruns. We could slightly improve this by e.g. searching for another + // always applicable candidate which doesn't depend on any cycle heads. + // + // NOTE: This is optimization is observable in case there is an always + // applicable global candidate and another non-global candidate which only + // applies because of a provisional result. I can't even think of a test + // case where this would occur and even then, this would not be unsound. + // Supporting this makes the code more involved, so I am just going to + // ignore this for now. + MergeCandidateInfo::AlwaysApplicable(i) => { + for (j, c) in where_bounds.into_iter().enumerate() { + if i != j { + self.ignore_candidate_head_usages(c.head_usages) } - // If a where-bound does not apply, we don't actually get a - // candidate for it. We manually track the head usages - // of all failed `ParamEnv` candidates instead. - self.ignore_candidate_head_usages( - failed_candidate_info.param_env_head_usages, - ); } - MergeCandidateInfo::EqualResponse => {} + // If a where-bound does not apply, we don't actually get a + // candidate for it. We manually track the head usages + // of all failed `ParamEnv` candidates instead. + self.ignore_candidate_head_usages(failed_candidate_info.param_env_head_usages); } - return Ok((response, Some(TraitGoalProvenVia::ParamEnv))); - } else { - return Ok((self.bail_with_ambiguity(&where_bounds), None)); - }; + MergeCandidateInfo::EqualResponse => {} + } + return Ok((response, Some(TraitGoalProvenVia::ParamEnv))); } // Next, prefer any alias bound (nested or otherwise). diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b2c72f19b78be..8634274c3a751 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1363,7 +1363,10 @@ impl DepNodeColorMap { Ordering::Relaxed, ) { Ok(_) => Ok(()), - Err(v) => Err(DepNodeIndex::from_u32(v)), + Err(v) => Err({ + assert_ne!(v, COMPRESSED_RED, "tried to mark a red node as green"); + DepNodeIndex::from_u32(v) + }), } } @@ -1384,7 +1387,9 @@ impl DepNodeColorMap { #[inline] pub(super) fn insert_red(&self, index: SerializedDepNodeIndex) { - self.values[index].store(COMPRESSED_RED, Ordering::Release) + let value = self.values[index].swap(COMPRESSED_RED, Ordering::Release); + // Sanity check for duplicate nodes + assert_eq!(value, COMPRESSED_UNKNOWN, "trying to encode a dep node twice"); } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e38d4370d5d25..5587fc91216ff 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -771,36 +771,39 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { None }; - // Skip ambiguity errors for extern flag bindings "overridden" - // by extern item bindings. - // FIXME: Remove with lang team approval. - let issue_145575_hack = Some(binding) == extern_prelude_flag_binding - && extern_prelude_item_binding.is_some() - && extern_prelude_item_binding != Some(innermost_binding); - if let Some(kind) = ambiguity_error_kind - && !issue_145575_hack - { - let misc = |f: Flags| { - if f.contains(Flags::MISC_SUGGEST_CRATE) { - AmbiguityErrorMisc::SuggestCrate - } else if f.contains(Flags::MISC_SUGGEST_SELF) { - AmbiguityErrorMisc::SuggestSelf - } else if f.contains(Flags::MISC_FROM_PRELUDE) { - AmbiguityErrorMisc::FromPrelude - } else { - AmbiguityErrorMisc::None - } - }; - self.ambiguity_errors.push(AmbiguityError { - kind, - ident: orig_ident, - b1: innermost_binding, - b2: binding, - warning: false, - misc1: misc(innermost_flags), - misc2: misc(flags), - }); - return true; + if let Some(kind) = ambiguity_error_kind { + // Skip ambiguity errors for extern flag bindings "overridden" + // by extern item bindings. + // FIXME: Remove with lang team approval. + let issue_145575_hack = Some(binding) == extern_prelude_flag_binding + && extern_prelude_item_binding.is_some() + && extern_prelude_item_binding != Some(innermost_binding); + + if issue_145575_hack { + self.issue_145575_hack_applied = true; + } else { + let misc = |f: Flags| { + if f.contains(Flags::MISC_SUGGEST_CRATE) { + AmbiguityErrorMisc::SuggestCrate + } else if f.contains(Flags::MISC_SUGGEST_SELF) { + AmbiguityErrorMisc::SuggestSelf + } else if f.contains(Flags::MISC_FROM_PRELUDE) { + AmbiguityErrorMisc::FromPrelude + } else { + AmbiguityErrorMisc::None + } + }; + self.ambiguity_errors.push(AmbiguityError { + kind, + ident: orig_ident, + b1: innermost_binding, + b2: binding, + warning: false, + misc1: misc(innermost_flags), + misc2: misc(flags), + }); + return true; + } } false diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4ef87af560504..4e0f3db59821f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1170,7 +1170,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } if let Some(initial_res) = initial_res { - if res != initial_res { + if res != initial_res && !this.issue_145575_hack_applied { span_bug!(import.span, "inconsistent resolution for an import"); } } else if this.privacy_errors.is_empty() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 50e11fdde5684..1c879837d6ed6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -28,7 +28,9 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::{AssocTag, DelegationFnSig, Visibility}; +use rustc_middle::ty::{ + AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationFnSig, DelegationFnSigAttrs, Visibility, +}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; @@ -5297,13 +5299,37 @@ impl ItemInfoCollector<'_, '_, '_> { id: NodeId, attrs: &[Attribute], ) { + static NAMES_TO_FLAGS: &[(Symbol, DelegationFnSigAttrs)] = &[ + (sym::target_feature, DelegationFnSigAttrs::TARGET_FEATURE), + (sym::must_use, DelegationFnSigAttrs::MUST_USE), + ]; + + let mut to_inherit_attrs = AttrVec::new(); + let mut attrs_flags = DelegationFnSigAttrs::empty(); + + 'attrs_loop: for attr in attrs { + for &(name, flag) in NAMES_TO_FLAGS { + if attr.has_name(name) { + attrs_flags.set(flag, true); + + if flag.bits() >= DELEGATION_INHERIT_ATTRS_START.bits() { + to_inherit_attrs.push(attr.clone()); + } + + continue 'attrs_loop; + } + } + } + let sig = DelegationFnSig { header, param_count: decl.inputs.len(), has_self: decl.has_self(), c_variadic: decl.c_variadic(), - target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)), + attrs_flags, + to_inherit_attrs, }; + self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 069944b638c71..233a4c48862ac 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1537,86 +1537,80 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Given `where ::Baz: String`, suggest `where T: Bar`. fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool { // Detect that we are actually in a `where` predicate. - let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate { + let Some(ast::WherePredicate { kind: ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate { bounded_ty, bound_generic_params, bounds, }), - span, + span: where_span, .. }) = self.diag_metadata.current_where_predicate - { - if !bound_generic_params.is_empty() { - return false; - } - (bounded_ty, bounds, span) - } else { + else { return false; }; + if !bound_generic_params.is_empty() { + return false; + } // Confirm that the target is an associated type. - let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind { - // use this to verify that ident is a type param. - let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { - return false; - }; - if !matches!( - partial_res.full_res(), - Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) - ) { - return false; - } - (&qself.ty, qself.position, path) - } else { + let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false }; + // use this to verify that ident is a type param. + let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false }; + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) + ) { return false; - }; + } - let peeled_ty = ty.peel_refs(); - if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind { - // Confirm that the `SelfTy` is a type parameter. - let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { + let peeled_ty = qself.ty.peel_refs(); + let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false }; + // Confirm that the `SelfTy` is a type parameter. + let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { + return false; + }; + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) + ) { + return false; + } + let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) = + (&type_param_path.segments[..], &bounds[..]) + else { + return false; + }; + let [ast::PathSegment { ident, args: None, id }] = + &poly_trait_ref.trait_ref.path.segments[..] + else { + return false; + }; + if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE { + return false; + } + if ident.span == span { + let Some(partial_res) = self.r.partial_res_map.get(&id) else { return false; }; - if !matches!( - partial_res.full_res(), - Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) - ) { + if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) { return false; } - if let ( - [ast::PathSegment { args: None, .. }], - [ast::GenericBound::Trait(poly_trait_ref)], - ) = (&type_param_path.segments[..], &bounds[..]) - && let [ast::PathSegment { ident, args: None, id }] = - &poly_trait_ref.trait_ref.path.segments[..] - && poly_trait_ref.modifiers == ast::TraitBoundModifiers::NONE - { - if ident.span == span { - let Some(partial_res) = self.r.partial_res_map.get(&id) else { - return false; - }; - if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) { - return false; - } - let Some(new_where_bound_predicate) = - mk_where_bound_predicate(path, poly_trait_ref, ty) - else { - return false; - }; - err.span_suggestion_verbose( - *where_span, - format!("constrain the associated type to `{ident}`"), - where_bound_predicate_to_string(&new_where_bound_predicate), - Applicability::MaybeIncorrect, - ); - } - return true; - } + let Some(new_where_bound_predicate) = + mk_where_bound_predicate(path, poly_trait_ref, &qself.ty) + else { + return false; + }; + err.span_suggestion_verbose( + *where_span, + format!("constrain the associated type to `{ident}`"), + where_bound_predicate_to_string(&new_where_bound_predicate), + Applicability::MaybeIncorrect, + ); } - false + true } /// Check if the source is call expression and the first argument is `self`. If true, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0b4ec6956bd15..b3141406e467e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,6 +10,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![deny(clippy::manual_let_else)] #![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -1187,6 +1188,7 @@ pub struct Resolver<'ra, 'tcx> { privacy_errors: Vec> = Vec::new(), /// Ambiguity errors are delayed for deduplication. ambiguity_errors: Vec> = Vec::new(), + issue_145575_hack_applied: bool = false, /// `use` injections are delayed for better placement and deduplication. use_injections: Vec> = Vec::new(), /// Crate-local macro expanded `macro_export` referred to by a module-relative path. diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index bd6fd5a3de428..53b1f9292b3d4 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -15,6 +15,10 @@ struct Timespec { } impl Timespec { + const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1); + + const MIN: Timespec = Self::new(i64::MIN, 0); + const fn zero() -> Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } @@ -209,6 +213,10 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) } diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index db4cf2804bf13..a9a448226619e 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -28,6 +28,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { SystemTime(usercalls::insecure_time()) } diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index c39d715c6a6f6..d5cf70f94c987 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -10,6 +10,10 @@ pub struct SystemTime(abi::time_t); pub const UNIX_EPOCH: SystemTime = SystemTime(0); impl SystemTime { + pub const MAX: SystemTime = SystemTime(abi::time_t::MAX); + + pub const MIN: SystemTime = SystemTime(abi::time_t::MIN); + pub fn now() -> SystemTime { let rtc = unsafe { let mut out = MaybeUninit::zeroed(); diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 28dacbe3068a7..30df6d93d0eed 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -70,6 +70,23 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = MAX_UEFI_TIME; + + pub const MIN: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { + year: 1900, + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0, + nanosecond: 0, + timezone: -1440, + daylight: 0, + pad1: 0, + pad2: 0, + }) + .unwrap(); + pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option { match system_time_internal::from_uefi(&t) { Some(x) => Some(Self(x)), diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 24f13853b96b3..1b3fbeee4d900 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -30,6 +30,10 @@ pub(crate) struct Timespec { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? }) @@ -62,6 +66,13 @@ impl fmt::Debug for SystemTime { } impl Timespec { + const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) }; + + // As described below, on Apple OS, dates before epoch are represented differently. + // This is not an issue here however, because we are using tv_sec = i64::MIN, + // which will cause the compatibility wrapper to not be executed at all. + const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) }; + const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } } diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 6d67b538a96bf..9bdd57268fd5b 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -27,6 +27,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { panic!("time not implemented on this platform") } diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 0d31b80e56afc..88f4d4cdbd615 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -64,6 +64,16 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { + t: c::FILETIME { + dwLowDateTime: (i64::MAX & 0xFFFFFFFF) as u32, + dwHighDateTime: (i64::MAX >> 32) as u32, + }, + }; + + pub const MIN: SystemTime = + SystemTime { t: c::FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 } }; + pub fn now() -> SystemTime { unsafe { let mut t: SystemTime = mem::zeroed(); diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index ae8be81c0b7c5..1e7e48183e982 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -35,6 +35,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { let result = blocking_scalar(systime_server(), GetUtcTimeMs.into()) .expect("failed to request utc time in ms"); diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 87aaf9091f1bc..0bda83af4dfb6 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -511,6 +511,69 @@ impl SystemTime { #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; + /// Represents the maximum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive addition to [`SystemTime::MAX`] will fail. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Adding zero will change nothing. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + /// + /// // But adding just 1ns will already fail. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a certificate with a timestamp in the + /// // future as a practical example. + /// let configured_offset = Duration::from_secs(60 * 60 * 24); + /// let valid_after = + /// SystemTime::now() + /// .checked_add(configured_offset) + /// .unwrap_or(SystemTime::MAX); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MAX: SystemTime = SystemTime(time::SystemTime::MAX); + + /// Represents the minimum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive subtraction from [`SystemTime::MIN`] will fail. + /// + /// Depending on the platform, this may be either less than or equal to + /// [`SystemTime::UNIX_EPOCH`], depending on whether the operating system + /// supports the representation of timestamps before the Unix epoch or not. + /// However, it is always guaranteed that a [`SystemTime::UNIX_EPOCH`] fits + /// between a [`SystemTime::MIN`] and [`SystemTime::MAX`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Subtracting zero will change nothing. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + /// + /// // But subtracting just 1ns will already fail. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a cache expiry as a practical example. + /// let configured_expiry = Duration::from_secs(60 * 3); + /// let expiry_threshold = + /// SystemTime::now() + /// .checked_sub(configured_expiry) + /// .unwrap_or(SystemTime::MIN); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MIN: SystemTime = SystemTime(time::SystemTime::MIN); + /// Returns the system time corresponding to "now". /// /// # Examples diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index be1948af91564..31cc7171fe52e 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -1,4 +1,5 @@ #![feature(duration_constants)] +#![feature(time_systemtime_limits)] use std::fmt::Debug; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -237,9 +238,27 @@ fn system_time_duration_since_max_range_on_unix() { let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0)); let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999)); + assert_eq!(min, SystemTime::MIN); + assert_eq!(max, SystemTime::MAX); + let delta_a = max.duration_since(min).expect("duration_since overflow"); let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration(); assert_eq!(Duration::MAX, delta_a); assert_eq!(Duration::MAX, delta_b); } + +#[test] +fn system_time_max_min() { + // First, test everything with checked_* and Duration::ZERO. + assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MAX.checked_sub(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MIN.checked_add(Duration::ZERO), Some(SystemTime::MIN)); + assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + + // Now do the same again with checked_* but try by ± a single nanosecond. + assert!(SystemTime::MAX.checked_add(Duration::new(0, 1)).is_none()); + assert!(SystemTime::MAX.checked_sub(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_add(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_sub(Duration::new(0, 1)).is_none()); +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a699cd23fb607..f30641d71e839 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2401,7 +2401,6 @@ Please disable assertions with `rust.debug-assertions = false`. let git_config = builder.config.git_config(); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email); - cmd.force_coloring_in_ci(); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 2ca52c72e5ec7..5a6bade59a6a3 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -2,6 +2,8 @@ use std::env; use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; +use build_helper::ci::CiEnv; + use super::{Builder, Kind}; use crate::core::build_steps::test; use crate::core::build_steps::tool::SourceType; @@ -1334,7 +1336,13 @@ impl Builder<'_> { // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - cargo.force_coloring_in_ci(); + if CiEnv::is_ci() { + // Tell cargo to use colored output for nicer logs in CI, even + // though CI isn't printing to a terminal. + // Also set an explicit `TERM=xterm` so that cargo doesn't warn + // about TERM not being set. + cargo.env("TERM", "xterm").args(["--color=always"]); + }; // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index f875e6e1af75c..61b8b26dceaf4 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -21,7 +21,6 @@ use std::process::{ use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use build_helper::ci::CiEnv; use build_helper::drop_bomb::DropBomb; use build_helper::exit; @@ -390,18 +389,6 @@ impl<'a> BootstrapCommand { self.drop_bomb.get_created_location() } - /// If in a CI environment, forces the command to run with colors. - pub fn force_coloring_in_ci(&mut self) { - if CiEnv::is_ci() { - // Due to use of stamp/docker, the output stream of bootstrap is not - // a TTY in CI, so coloring is by-default turned off. - // The explicit `TERM=xterm` environment is needed for - // `--color always` to actually work. This env var was lost when - // compiling through the Makefile. Very strange. - self.env("TERM", "xterm").args(["--color", "always"]); - } - } - pub fn fingerprint(&self) -> CommandFingerprint { let command = &self.command; CommandFingerprint { diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 1fa818df62dea..71dad36337932 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -136,8 +136,6 @@ fn parse_config(args: Vec) -> Config { ) .optflag("", "fail-fast", "stop as soon as possible after any test fails") .optopt("", "target", "the target to build for", "TARGET") - // FIXME: Should be removed once `bootstrap` will be updated to not use this option. - .optopt("", "color", "coloring: auto, always, never", "WHEN") .optopt("", "host", "the host to build for", "HOST") .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") diff --git a/tests/pretty/auxiliary/to-reuse-functions.rs b/tests/pretty/auxiliary/to-reuse-functions.rs new file mode 100644 index 0000000000000..55d6ecf035e34 --- /dev/null +++ b/tests/pretty/auxiliary/to-reuse-functions.rs @@ -0,0 +1,14 @@ +//@ edition:2021 + +#[must_use] +#[cold] +pub unsafe fn unsafe_fn_extern() -> usize { 1 } + +#[must_use = "extern_fn_extern: some reason"] +#[deprecated] +pub extern "C" fn extern_fn_extern() -> usize { 1 } + +pub const fn const_fn_extern() -> usize { 1 } + +#[must_use] +pub async fn async_fn_extern() { } diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp new file mode 100644 index 0000000000000..772e177b88835 --- /dev/null +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -0,0 +1,61 @@ +//@ edition:2021 +//@ aux-crate:to_reuse_functions=to-reuse-functions.rs +//@ pretty-mode:hir +//@ pretty-compare-only +//@ pp-exact:delegation-inherit-attributes.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#[attr = MacroUse {arguments: UseAll}] +extern crate std; +#[prelude_import] +use std::prelude::rust_2021::*; + +extern crate to_reuse_functions; + +mod to_reuse { + #[attr = MustUse {reason: "foo: some reason"}] + #[attr = Cold] + fn foo(x: usize) -> usize { x } + + #[attr = MustUse] + #[attr = Cold] + fn foo_no_reason(x: usize) -> usize { x } + + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Cold] + fn bar(x: usize) -> usize { x } +} + +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = MustUse {reason: "foo: some reason"}] +#[attr = Inline(Hint)] +fn foo1(arg0: _) -> _ { to_reuse::foo(self + 1) } + +#[attr = MustUse] +#[attr = Inline(Hint)] +fn foo_no_reason(arg0: _) -> _ { to_reuse::foo_no_reason(self + 1) } + +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = MustUse {reason: "some reason"}] +#[attr = Inline(Hint)] +fn foo2(arg0: _) -> _ { to_reuse::foo(self + 1) } + +#[attr = Inline(Hint)] +fn bar(arg0: _) -> _ { to_reuse::bar(arg0) } + +#[attr = MustUse] +#[attr = Inline(Hint)] +unsafe fn unsafe_fn_extern() -> _ { to_reuse_functions::unsafe_fn_extern() } +#[attr = MustUse {reason: "extern_fn_extern: some reason"}] +#[attr = Inline(Hint)] +extern "C" fn extern_fn_extern() + -> _ { to_reuse_functions::extern_fn_extern() } +#[attr = Inline(Hint)] +const fn const_fn_extern() -> _ { to_reuse_functions::const_fn_extern() } +#[attr = MustUse {reason: "some reason"}] +#[attr = Inline(Hint)] +async fn async_fn_extern() -> _ { to_reuse_functions::async_fn_extern() } + + +fn main() { } diff --git a/tests/pretty/delegation-inherit-attributes.rs b/tests/pretty/delegation-inherit-attributes.rs new file mode 100644 index 0000000000000..fe74b9a55a7d7 --- /dev/null +++ b/tests/pretty/delegation-inherit-attributes.rs @@ -0,0 +1,56 @@ +//@ edition:2021 +//@ aux-crate:to_reuse_functions=to-reuse-functions.rs +//@ pretty-mode:hir +//@ pretty-compare-only +//@ pp-exact:delegation-inherit-attributes.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +extern crate to_reuse_functions; + +mod to_reuse { + #[must_use = "foo: some reason"] + #[cold] + pub fn foo(x: usize) -> usize { + x + } + + #[must_use] + #[cold] + pub fn foo_no_reason(x: usize) -> usize { + x + } + + #[cold] + #[deprecated] + pub fn bar(x: usize) -> usize { + x + } +} + +#[deprecated] +reuse to_reuse::foo as foo1 { + self + 1 +} + +reuse to_reuse::foo_no_reason { + self + 1 +} + +#[deprecated] +#[must_use = "some reason"] +reuse to_reuse::foo as foo2 { + self + 1 +} + +reuse to_reuse::bar; + +reuse to_reuse_functions::unsafe_fn_extern; +reuse to_reuse_functions::extern_fn_extern; +reuse to_reuse_functions::const_fn_extern; +#[must_use = "some reason"] +reuse to_reuse_functions::async_fn_extern; + + +fn main() {} diff --git a/tests/ui/issues/issue-4265.stderr b/tests/ui/issues/issue-4265.stderr index 23d00aaa44b54..d4a44c129a89e 100644 --- a/tests/ui/issues/issue-4265.stderr +++ b/tests/ui/issues/issue-4265.stderr @@ -14,10 +14,7 @@ LL | struct Foo { | ---------- method `bar` not found for this struct ... LL | Foo { baz: 0 }.bar(); - | ---------------^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Foo::bar()` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Foo` @@ -25,6 +22,11 @@ note: the candidate is defined in an impl for the type `Foo` | LL | fn bar() { | ^^^^^^^^ +help: use associated function syntax instead + | +LL - Foo { baz: 0 }.bar(); +LL + Foo::bar(); + | error: aborting due to 2 previous errors diff --git a/tests/ui/methods/assc-func-issue-149038.rs b/tests/ui/methods/assc-func-issue-149038.rs new file mode 100644 index 0000000000000..4fb4bd72fcc30 --- /dev/null +++ b/tests/ui/methods/assc-func-issue-149038.rs @@ -0,0 +1,10 @@ +struct S; +impl S { + fn foo() {} + fn bar(&self) { + self.foo(); //~ ERROR no method named `foo` found for reference `&S` in the current scope + let f: fn() = self.foo; //~ ERROR no field `foo` on type `&S` + } +} + +fn main() {} diff --git a/tests/ui/methods/assc-func-issue-149038.stderr b/tests/ui/methods/assc-func-issue-149038.stderr new file mode 100644 index 0000000000000..55b762bc0ee02 --- /dev/null +++ b/tests/ui/methods/assc-func-issue-149038.stderr @@ -0,0 +1,43 @@ +error[E0599]: no method named `foo` found for reference `&S` in the current scope + --> $DIR/assc-func-issue-149038.rs:5:14 + | +LL | self.foo(); + | ^^^ this is an associated function, not a method + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in an impl for the type `S` + --> $DIR/assc-func-issue-149038.rs:3:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: use associated function syntax instead + | +LL - self.foo(); +LL + S::foo(); + | + +error[E0609]: no field `foo` on type `&S` + --> $DIR/assc-func-issue-149038.rs:6:28 + | +LL | let f: fn() = self.foo; + | ^^^ + | | + | this is an associated function, not a method + | unknown field + | + = note: found the following associated function; to be used as method, it must have a `self` parameter +note: the candidate is defined in an impl for the type `S` + --> $DIR/assc-func-issue-149038.rs:3:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: use associated function syntax instead + | +LL - let f: fn() = self.foo; +LL + let f: fn() = S::foo; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0599, E0609. +For more information about an error, try `rustc --explain E0599`. diff --git a/tests/ui/methods/issue-3707.stderr b/tests/ui/methods/issue-3707.stderr index b3d4dfe5aaa88..c163ccc81899a 100644 --- a/tests/ui/methods/issue-3707.stderr +++ b/tests/ui/methods/issue-3707.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `boom` found for reference `&Obj` in the current s --> $DIR/issue-3707.rs:10:14 | LL | self.boom(); - | -----^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Obj::boom()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Obj` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `Obj` | LL | pub fn boom() -> bool { | ^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - self.boom(); +LL + Obj::boom(); + | error: aborting due to 1 previous error diff --git a/tests/ui/resolve/ice-inconsistent-resolution-149821.rs b/tests/ui/resolve/ice-inconsistent-resolution-149821.rs new file mode 100644 index 0000000000000..19b8a2f4330c4 --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-149821.rs @@ -0,0 +1,17 @@ +//@ edition: 2024 + +mod m { + use crate::*; + use core; +} + +macro_rules! define_other_core { + () => { + extern crate std as core; + //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` + }; +} + +define_other_core! {} + +fn main() {} diff --git a/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr b/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr new file mode 100644 index 0000000000000..cd75a2f3e19b7 --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr @@ -0,0 +1,13 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/ice-inconsistent-resolution-149821.rs:10:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core! {} + | --------------------- in this macro invocation + | + = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/suggestions/issue-102354.stderr b/tests/ui/suggestions/issue-102354.stderr index 8340d9340f9b2..9354ce3efe57d 100644 --- a/tests/ui/suggestions/issue-102354.stderr +++ b/tests/ui/suggestions/issue-102354.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `func` found for type `i32` in the current scope --> $DIR/issue-102354.rs:9:7 | LL | x.func(); - | --^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `i32::func()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `Trait` @@ -13,6 +10,11 @@ note: the candidate is defined in the trait `Trait` | LL | fn func() {} | ^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.func(); +LL + i32::func(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-103646.stderr b/tests/ui/suggestions/issue-103646.stderr index 8d0e8652392d6..42505e13e7e68 100644 --- a/tests/ui/suggestions/issue-103646.stderr +++ b/tests/ui/suggestions/issue-103646.stderr @@ -4,10 +4,7 @@ error[E0599]: no method named `nya` found for type parameter `T` in the current LL | fn uwu(c: T) { | - method `nya` not found for this type parameter LL | c.nya(); - | --^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `T::nya()` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `Cat` @@ -15,6 +12,11 @@ note: the candidate is defined in the trait `Cat` | LL | fn nya() {} | ^^^^^^^^ +help: use associated function syntax instead + | +LL - c.nya(); +LL + T::nya(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr index a30b78692146b..2314ff378f641 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `test` found for struct `Box>` in the cur --> $DIR/suggest-assoc-fn-call-deref.rs:13:7 | LL | x.test(); - | --^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Foo::::test()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Foo` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `Foo` | LL | fn test() -> i32 { 1 } | ^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.test(); +LL + Foo::::test(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr index 0df2b08d3be82..4ff4c50f17902 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr @@ -5,10 +5,7 @@ LL | struct A { | -------- method `foo` not found for this struct ... LL | _a.foo(); - | ---^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::foo(_a)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -16,6 +13,11 @@ note: the candidate is defined in the trait `M` | LL | fn foo(_a: Self); | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.foo(); +LL + A::foo(_a); + | error[E0599]: no method named `baz` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:23:8 @@ -24,10 +26,7 @@ LL | struct A { | -------- method `baz` not found for this struct ... LL | _a.baz(0); - | ---^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::baz(0)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -35,6 +34,11 @@ note: the candidate is defined in the trait `M` | LL | fn baz(_a: i32); | ^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.baz(0); +LL + A::baz(0); + | error[E0599]: no method named `bar` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:27:8 @@ -43,10 +47,7 @@ LL | struct A { | -------- method `bar` not found for this struct ... LL | _b.bar(); - | ---^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::bar(_b)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -54,6 +55,11 @@ note: the candidate is defined in the trait `M` | LL | fn bar(_a: Self); | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.bar(); +LL + A::bar(_b); + | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr index 6e4c77deac50f..df8d80c4babfe 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr @@ -5,10 +5,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `default_hello` not found for this struct ... LL | x.default_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::default_hello()` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn default_hello() {} | ^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.default_hello(); +LL + GenericAssocMethod::<_>::default_hello(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr index 1bc2592944699..99d206764a17e 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMetho --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11 | LL | state.hello(); - | ------^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `HasAssocMethod::hello()` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `HasAssocMethod` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `HasAssocMethod` | LL | fn hello() {} | ^^^^^^^^^^ +help: use associated function syntax instead + | +LL - state.hello(); +LL + HasAssocMethod::hello(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr index 92b03fc77142c..56d6b9fcd143d 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr @@ -5,10 +5,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_ref_hello` not found for this struct ... LL | x.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello(&x)` + | ^^^^^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_ref_hello(_: &Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.self_ty_ref_hello(); +LL + GenericAssocMethod::<_>::self_ty_ref_hello(&x); + | error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:16:7 @@ -24,10 +26,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | x.self_ty_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello(x)` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -35,6 +34,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_hello(_: Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.self_ty_hello(); +LL + GenericAssocMethod::<_>::self_ty_hello(x); + | error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:20:7 @@ -43,10 +47,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `default_hello` not found for this struct ... LL | y.default_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::default_hello()` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -54,6 +55,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn default_hello() {} | ^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.default_hello(); +LL + GenericAssocMethod::::default_hello(); + | error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:22:7 @@ -62,10 +68,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_ref_hello` not found for this struct ... LL | y.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_ref_hello(&y)` + | ^^^^^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -73,6 +76,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_ref_hello(_: &Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.self_ty_ref_hello(); +LL + GenericAssocMethod::::self_ty_ref_hello(&y); + | error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:24:7 @@ -81,10 +89,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | y.self_ty_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_hello(y)` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -92,6 +97,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_hello(_: Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.self_ty_hello(); +LL + GenericAssocMethod::::self_ty_hello(y); + | error: aborting due to 5 previous errors diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr index 793595784d937..a09cf41488df9 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr @@ -5,10 +5,7 @@ LL | struct A {} | -------- method `hello` not found for this struct ... LL | _a.hello(1); - | ---^^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::hello(1)` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `A` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `A` | LL | fn hello(_a: i32) {} | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.hello(1); +LL + A::hello(1); + | error[E0599]: no method named `test` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:22:8 @@ -24,10 +26,7 @@ LL | struct A {} | -------- method `test` not found for this struct ... LL | _a.test(1); - | ---^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::test(_a, 1)` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `A` @@ -35,6 +34,11 @@ note: the candidate is defined in an impl for the type `A` | LL | fn test(_a: Self, _b: i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.test(1); +LL + A::test(_a, 1); + | error[E0599]: no method named `hello` found for struct `B<&str>` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:26:8 @@ -43,10 +47,7 @@ LL | struct B { | ----------- method `hello` not found for this struct ... LL | _b.hello(1); - | ---^^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `B::<&str>::hello(1)` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `B` @@ -54,6 +55,11 @@ note: the candidate is defined in an impl for the type `B` | LL | fn hello(_a: i32) {} | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.hello(1); +LL + B::<&str>::hello(1); + | error[E0599]: no method named `test` found for struct `B<&str>` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:28:8 @@ -62,10 +68,7 @@ LL | struct B { | ----------- method `test` not found for this struct ... LL | _b.test(1); - | ---^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `B::<&str>::test(_b, 1)` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `B` @@ -73,6 +76,11 @@ note: the candidate is defined in an impl for the type `B` | LL | fn test(_a: Self, _b: i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.test(1); +LL + B::<&str>::test(_b, 1); + | error: aborting due to 4 previous errors