diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e92afc14c20d..dc8ac539a3a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,6 +182,11 @@ jobs: - name: install MinGW run: src/ci/scripts/install-mingw.sh + # Workaround for spurious ci failures after mingw install + # see https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Spurious.20bors.20CI.20failures/near/528915775 + - name: ensure home dir exists + run: mkdir -p ~ + - name: install ninja run: src/ci/scripts/install-ninja.sh diff --git a/Cargo.lock b/Cargo.lock index 51fd06972f28..b8a8d7b7d232 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5069,14 +5069,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "suggest-tests" -version = "0.1.0" -dependencies = [ - "build_helper", - "glob", -] - [[package]] name = "syn" version = "1.0.109" diff --git a/Cargo.toml b/Cargo.toml index 6d3425f4115a..67c7a9d67edc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,6 @@ members = [ "src/tools/rustdoc-gui-test", "src/tools/rustdoc-themes", "src/tools/rustfmt", - "src/tools/suggest-tests", "src/tools/test-float-parse", "src/tools/tidy", "src/tools/tier-check", diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs index 323a8fab6d59..069bff67b97a 100644 --- a/compiler/rustc_ast/src/expand/mod.rs +++ b/compiler/rustc_ast/src/expand/mod.rs @@ -1,24 +1,7 @@ //! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`. use rustc_macros::{Decodable, Encodable, HashStable_Generic}; -use rustc_span::Ident; -use rustc_span::def_id::DefId; - -use crate::MetaItem; pub mod allocator; pub mod autodiff_attrs; pub mod typetree; - -#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] -pub struct StrippedCfgItem { - pub parent_module: ModId, - pub ident: Ident, - pub cfg: MetaItem, -} - -impl StrippedCfgItem { - pub fn map_mod_id(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem { - StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } - } -} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 348fe2ee40aa..1c96a375035a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -42,7 +42,7 @@ use std::sync::Arc; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, *}; -use rustc_attr_parsing::{AttributeParser, OmitDoc}; +use rustc_attr_parsing::{AttributeParser, Late, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -192,7 +192,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), + attribute_parser: AttributeParser::new( + tcx.sess, + tcx.features(), + registered_tools, + Late, + ), delayed_lints: Vec::new(), } } diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9b14ed88978b..3dedeb1b3726 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -3,7 +3,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::{self as ast, AttrStyle}; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::hygiene::Transparency; -use rustc_span::{Span, Symbol}; +use rustc_span::{Ident, Span, Symbol}; use thin_vec::ThinVec; use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; @@ -69,6 +69,7 @@ pub enum ReprAttr { ReprAlign(Align), } pub use ReprAttr::*; +use rustc_span::def_id::DefId; pub enum TransparencyError { UnknownTransparency(Symbol, Span), @@ -140,6 +141,30 @@ pub enum UsedBy { Linker, } +#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] +pub struct StrippedCfgItem { + pub parent_module: ModId, + pub ident: Ident, + pub cfg: (CfgEntry, Span), +} + +impl StrippedCfgItem { + pub fn map_mod_id(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem { + StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } + } +} + +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum CfgEntry { + All(ThinVec, Span), + Any(ThinVec, Span), + Not(Box, Span), + Bool(bool, Span), + NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span }, + Version(Option, Span), +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -349,6 +374,9 @@ pub enum AttributeKind { /// Represents `#[path]` Path(Symbol, Span), + /// Represents `#[pointee]` + Pointee(Span), + /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). PubTransparent(Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 494b570c86c7..3e2dc0a15b2f 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -57,6 +57,7 @@ impl AttributeKind { ParenSugar(..) => No, PassByValue(..) => Yes, Path(..) => No, + Pointee(..) => No, PubTransparent(..) => Yes, Repr { .. } => No, RustcLayoutScalarValidRangeEnd(..) => Yes, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index a8d9229cbc35..a56855b3bd3d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,247 +1,291 @@ -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::RustcVersion; -use rustc_feature::{Features, GatedCfg, find_gated_cfg}; +use rustc_ast::{LitKind, NodeId}; +use rustc_attr_data_structures::{CfgEntry, RustcVersion}; +use rustc_feature::{AttributeTemplate, Features, template}; use rustc_session::Session; use rustc_session::config::ExpectedValues; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; -use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; -use crate::{fluent_generated, parse_version}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; +use crate::{ + CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, +}; -/// 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); +pub const CFG_TEMPLATE: AttributeTemplate = template!(List: "predicate"); + +pub fn parse_cfg_attr<'c, S: Stage>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, +) -> Option { + let ArgParser::List(list) = args else { + cx.expected_list(cx.attr_span); + return None; + }; + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + parse_cfg_entry(cx, single) } -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, -} - -/// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches( - cfg: &MetaItemInner, - sess: &Session, - lint_emitter: impl CfgMatchesLintEmitter, - features: Option<&Features>, -) -> bool { - eval_condition(cfg, sess, features, &mut |cfg| { - try_gate_cfg(cfg.name, cfg.span, sess, features); - match sess.psess.check_config.expecteds.get(&cfg.name) { - Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => { - lint_emitter.emit_span_lint( - sess, - UNEXPECTED_CFGS, - cfg.span, - BuiltinLintDiag::UnexpectedCfgValue( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), - ); +fn parse_cfg_entry( + cx: &mut AcceptContext<'_, '_, S>, + item: &MetaItemOrLitParser<'_>, +) -> Option { + Some(match item { + MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { + ArgParser::List(list) => match meta.path().word_sym() { + Some(sym::not) => { + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span) + } + Some(sym::any) => CfgEntry::Any( + list.mixed().flat_map(|sub_item| parse_cfg_entry(cx, sub_item)).collect(), + list.span, + ), + Some(sym::all) => CfgEntry::All( + list.mixed().flat_map(|sub_item| parse_cfg_entry(cx, sub_item)).collect(), + list.span, + ), + Some(sym::target) => parse_cfg_entry_target(cx, list, meta.span())?, + Some(sym::version) => parse_cfg_entry_version(cx, list, meta.span())?, + _ => { + cx.emit_err(session_diagnostics::InvalidPredicate { + span: meta.span(), + predicate: meta.path().to_string(), + }); + return None; + } + }, + a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => { + let Some(name) = meta.path().word_sym() else { + cx.emit_err(session_diagnostics::CfgPredicateIdentifier { + span: meta.path().span(), + }); + return None; + }; + parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)? } - None if sess.psess.check_config.exhaustive_names => { - lint_emitter.emit_span_lint( - sess, - UNEXPECTED_CFGS, - cfg.span, - BuiltinLintDiag::UnexpectedCfgName( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), - ); + }, + MetaItemOrLitParser::Lit(lit) => match lit.kind { + LitKind::Bool(b) => CfgEntry::Bool(b, lit.span), + _ => { + cx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: lit.span }); + return None; } - _ => { /* not unexpected */ } - } - sess.psess.config.contains(&(cfg.name, cfg.value)) + }, + MetaItemOrLitParser::Err(_, _) => return None, }) } -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); - } +fn parse_cfg_entry_version( + cx: &mut AcceptContext<'_, '_, S>, + list: &MetaItemListParser<'_>, + meta_span: Span, +) -> Option { + try_gate_cfg(sym::version, meta_span, cx.sess(), Some(cx.features())); + let Some(version) = list.single() else { + cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }); + return None; + }; + let Some(version_lit) = version.lit() else { + cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version.span() }); + return None; + }; + let Some(version_str) = version_lit.value_str() else { + cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version_lit.span }); + return None; + }; + + let min_version = parse_version(version_str).or_else(|| { + cx.sess() + .dcx() + .emit_warn(session_diagnostics::UnknownVersionLiteral { span: version_lit.span }); + None + }); + + Some(CfgEntry::Version(min_version, list.span)) } -#[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(); +fn parse_cfg_entry_target( + cx: &mut AcceptContext<'_, '_, S>, + list: &MetaItemListParser<'_>, + meta_span: Span, +) -> Option { + if !cx.features().cfg_target_compact() { + feature_err( + cx.sess(), + sym::cfg_target_compact, + meta_span, + fluent_generated::attr_parsing_unstable_cfg_target_compact, + ) + .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 mut result = ThinVec::new(); + for sub_item in list.mixed() { + // First, validate that this is a NameValue item + let Some(sub_item) = sub_item.meta_item() else { + cx.expected_name_value(sub_item.span(), None); + continue; + }; + let Some(nv) = sub_item.args().name_value() else { + cx.expected_name_value(sub_item.span(), None); + continue; + }; - 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()), + // Then, parse it as a name-value item + let Some(name) = sub_item.path().word_sym() else { + cx.emit_err(session_diagnostics::CfgPredicateIdentifier { + span: sub_item.path().span(), }); - return false; + return None; + }; + let name = Symbol::intern(&format!("target_{name}")); + if let Some(cfg) = + parse_name_value(name, sub_item.path().span(), Some(nv), sub_item.span(), cx) + { + result.push(cfg); + } + } + Some(CfgEntry::All(result, list.span)) +} + +fn parse_name_value( + name: Symbol, + name_span: Span, + value: Option<&NameValueParser>, + span: Span, + cx: &mut AcceptContext<'_, '_, S>, +) -> Option { + try_gate_cfg(name, span, cx.sess(), cx.features_option()); + + let value = match value { + None => None, + Some(value) => { + let Some(value_str) = value.value_as_str() else { + cx.expected_string_literal(value.value_span, Some(value.value_as_lit())); + return None; + }; + Some((value_str, value.value_span)) } }; - 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; - }; + Some(CfgEntry::NameValue { name, name_span, value, span }) +} - // 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; +pub fn eval_config_entry( + sess: &Session, + cfg_entry: &CfgEntry, + id: NodeId, + features: Option<&Features>, +) -> EvalConfigResult { + match cfg_entry { + CfgEntry::All(subs, ..) => { + let mut all = None; + for sub in subs { + let res = eval_config_entry(sess, sub, id, features); + // We cannot short-circuit because `eval_config_entry` emits some lints + if !res.as_bool() { + all.get_or_insert(res); } } - - // 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 + all.unwrap_or_else(|| EvalConfigResult::True) + } + CfgEntry::Any(subs, span) => { + let mut any = None; + for sub in subs { + let res = eval_config_entry(sess, sub, id, features); + // We cannot short-circuit because `eval_config_entry` emits some lints + if res.as_bool() { + any.get_or_insert(res); } } - } - MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { - 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, + any.unwrap_or_else(|| EvalConfigResult::False { + reason: cfg_entry.clone(), + reason_span: *span, }) } + CfgEntry::Not(sub, span) => { + if eval_config_entry(sess, sub, id, features).as_bool() { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } + } else { + EvalConfigResult::True + } + } + CfgEntry::Bool(b, span) => { + if *b { + EvalConfigResult::True + } else { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } + } + } + CfgEntry::NameValue { name, name_span, value, span } => { + match sess.psess.check_config.expecteds.get(name) { + Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), + ); + } + None if sess.psess.check_config.exhaustive_names => { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), + ); + } + _ => { /* not unexpected */ } + } + + if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) { + EvalConfigResult::True + } else { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } + } + } + CfgEntry::Version(min_version, version_span) => { + let Some(min_version) = min_version else { + return EvalConfigResult::False { + reason: cfg_entry.clone(), + reason_span: *version_span, + }; + }; + // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details + let min_version_ok = if sess.psess.assume_incomplete_release { + RustcVersion::current_overridable() > *min_version + } else { + RustcVersion::current_overridable() >= *min_version + }; + if min_version_ok { + EvalConfigResult::True + } else { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *version_span } + } + } + } +} + +pub enum EvalConfigResult { + True, + False { reason: CfgEntry, reason_span: Span }, +} + +impl EvalConfigResult { + pub fn as_bool(&self) -> bool { + match self { + EvalConfigResult::True => true, + EvalConfigResult::False { .. } => false, + } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs new file mode 100644 index 000000000000..c5025a8b6eac --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -0,0 +1,247 @@ +use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; +use rustc_ast_pretty::pprust; +use rustc_attr_data_structures::RustcVersion; +use rustc_feature::{Features, GatedCfg, find_gated_cfg}; +use rustc_session::Session; +use rustc_session::config::ExpectedValues; +use rustc_session::lint::builtin::UNEXPECTED_CFGS; +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, +} + +/// Tests if a cfg-pattern matches the cfg set +pub fn cfg_matches( + cfg: &MetaItemInner, + sess: &Session, + lint_emitter: impl CfgMatchesLintEmitter, + features: Option<&Features>, +) -> bool { + eval_condition(cfg, sess, features, &mut |cfg| { + try_gate_cfg(cfg.name, cfg.span, sess, features); + match sess.psess.check_config.expecteds.get(&cfg.name) { + Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => { + lint_emitter.emit_span_lint( + sess, + UNEXPECTED_CFGS, + cfg.span, + BuiltinLintDiag::UnexpectedCfgValue( + (cfg.name, cfg.name_span), + cfg.value.map(|v| (v, cfg.value_span.unwrap())), + ), + ); + } + None if sess.psess.check_config.exhaustive_names => { + lint_emitter.emit_span_lint( + sess, + UNEXPECTED_CFGS, + cfg.span, + BuiltinLintDiag::UnexpectedCfgName( + (cfg.name, cfg.name_span), + cfg.value.map(|v| (v, cfg.value_span.unwrap())), + ), + ); + } + _ => { /* not unexpected */ } + } + sess.psess.config.contains(&(cfg.name, cfg.value)) + }) +} + +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 => { + 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 68c716d1a99d..200f13819602 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -27,6 +27,7 @@ use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; pub(crate) mod cfg; +pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod deprecation; diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index ee8a33ae9c43..d5e088effd51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -145,3 +145,10 @@ impl NoArgsAttributeParser for FundamentalParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental; } + +pub(crate) struct PointeeParser; +impl NoArgsAttributeParser for PointeeParser { + const PATH: &[Symbol] = &[sym::pointee]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6c70f2ee4ee0..567341d1517d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -1,6 +1,5 @@ use std::cell::RefCell; use std::collections::BTreeMap; -use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; @@ -48,8 +47,8 @@ use crate::attributes::test_attrs::IgnoreParser; use crate::attributes::traits::{ AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, - ParenSugarParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser, - UnsafeSpecializationMarkerParser, + ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, + TypeConstParser, UnsafeSpecializationMarkerParser, }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; @@ -178,6 +177,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -202,7 +202,11 @@ pub trait Stage: Sized + 'static + Sealed { fn parsers() -> &'static group_type!(Self); - fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed; + fn emit_err<'sess>( + &self, + sess: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed; } // allow because it's a sealed trait @@ -214,8 +218,16 @@ impl Stage for Early { fn parsers() -> &'static group_type!(Self) { &early::ATTRIBUTE_PARSERS } - fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { - sess.dcx().create_err(diag).delay_as_bug() + fn emit_err<'sess>( + &self, + sess: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { + if self.emit_errors { + sess.dcx().emit_err(diag) + } else { + sess.dcx().create_err(diag).delay_as_bug() + } } } @@ -228,20 +240,29 @@ impl Stage for Late { fn parsers() -> &'static group_type!(Self) { &late::ATTRIBUTE_PARSERS } - fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + fn emit_err<'sess>( + &self, + tcx: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { tcx.dcx().emit_err(diag) } } /// used when parsing attributes for miscellaneous things *before* ast lowering -pub struct Early; +pub struct Early { + /// Whether to emit errors or delay them as a bug + /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed + /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted + pub emit_errors: bool, +} /// used when parsing attributes during ast lowering pub struct Late; /// Context given to every attribute parser when accepting /// /// Gives [`AttributeParser`]s enough information to create errors, for example. -pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { +pub struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) shared: SharedContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, @@ -257,7 +278,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { - S::emit_err(&self.sess, diag) + self.stage.emit_err(&self.sess, diag) } /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing @@ -472,7 +493,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create /// errors, for example. -pub(crate) struct SharedContext<'p, 'sess, S: Stage> { +pub struct SharedContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. pub(crate) cx: &'p mut AttributeParser<'sess, S>, @@ -540,7 +561,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> { pub(crate) tools: Vec, features: Option<&'sess Features>, sess: &'sess Session, - stage: PhantomData, + stage: S, /// *Only* parse attributes with this symbol. /// @@ -569,13 +590,14 @@ impl<'sess> AttributeParser<'sess, Early> { sym: Symbol, target_span: Span, target_node_id: NodeId, + features: Option<&'sess Features>, ) -> Option { let mut p = Self { - features: None, + features, tools: Vec::new(), parse_only: Some(sym), sess, - stage: PhantomData, + stage: Early { emit_errors: false }, }; let mut parsed = p.parse_attribute_list( attrs, @@ -591,11 +613,55 @@ impl<'sess> AttributeParser<'sess, Early> { parsed.pop() } + + pub fn parse_single( + sess: &'sess Session, + attr: &ast::Attribute, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + emit_errors: bool, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T, + template: &AttributeTemplate, + ) -> T { + let mut parser = Self { + features, + tools: Vec::new(), + parse_only: None, + sess, + stage: Early { emit_errors }, + }; + let ast::AttrKind::Normal(normal_attr) = &attr.kind else { + panic!("parse_single called on a doc attr") + }; + let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx()); + let path = meta_parser.path(); + let args = meta_parser.args(); + let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { + shared: SharedContext { + cx: &mut parser, + target_span, + target_id: target_node_id, + emit_lint: &mut |_lint| { + panic!("can't emit lints here for now (nothing uses this atm)"); + }, + }, + attr_span: attr.span, + template, + attr_path: path.get_attribute_path(), + }; + parse_fn(&mut cx, args) + } } impl<'sess, S: Stage> AttributeParser<'sess, S> { - pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { - Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } + pub fn new( + sess: &'sess Session, + features: &'sess Features, + tools: Vec, + stage: S, + ) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage } } pub(crate) fn sess(&self) -> &'sess Session { @@ -606,6 +672,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { self.features.expect("features not available at this point in the compiler") } + pub(crate) fn features_option(&self) -> Option<&'sess Features> { + self.features + } + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { self.sess().dcx() } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 47eeb63bad3d..2102a26108bc 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -90,7 +90,8 @@ mod lints; pub mod parser; mod session_diagnostics; -pub use attributes::cfg::*; +pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr}; +pub use attributes::cfg_old::*; pub use attributes::util::{ find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, }; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 8a240639d75a..97bf3d1c5495 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -593,7 +593,13 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.code(E0565); } AttributeParseErrorReason::ExpectedNameValue(None) => { - // The suggestion we add below this match already contains enough information + // If the span is the entire attribute, the suggestion we add below this match already contains enough information + if self.span != self.attr_span { + diag.span_label( + self.span, + format!("expected this to be of the form `... = \"...\"`"), + ); + } } AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { diag.span_label( diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 183927edb022..ae186d744c40 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -81,11 +81,11 @@ builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a l builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified -builtin_macros_cfg_select_no_matches = none of the rules in this `cfg_select` evaluated to true +builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true -builtin_macros_cfg_select_unreachable = unreachable rule +builtin_macros_cfg_select_unreachable = unreachable predicate .label = always matches - .label2 = this rules is never reached + .label2 = this predicate is never reached builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized` diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index 2dc387d5866a..f22d5f255c29 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,12 +1,12 @@ use rustc_ast::tokenstream::TokenStream; use rustc_attr_parsing as attr; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectRule, parse_cfg_select}; +use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select}; use rustc_span::{Ident, Span, sym}; use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; -/// Selects the first arm whose rule evaluates to true. +/// Selects the first arm whose predicate evaluates to true. fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { for (cfg, tt, arm_span) in branches.reachable { if attr::cfg_matches( @@ -30,11 +30,11 @@ pub(super) fn expand_cfg_select<'cx>( ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) { Ok(branches) => { if let Some((underscore, _, _)) = branches.wildcard { - // Warn for every unreachable rule. We store the fully parsed branch for rustfmt. - for (rule, _, _) in &branches.unreachable { - let span = match rule { - CfgSelectRule::Wildcard(underscore) => underscore.span, - CfgSelectRule::Cfg(cfg) => cfg.span(), + // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt. + for (predicate, _, _) in &branches.unreachable { + let span = match predicate { + CfgSelectPredicate::Wildcard(underscore) => underscore.span, + CfgSelectPredicate::Cfg(cfg) => cfg.span(), }; let err = CfgSelectUnreachable { span, wildcard_span: underscore.span }; ecx.dcx().emit_warn(err); @@ -50,7 +50,7 @@ pub(super) fn expand_cfg_select<'cx>( Ident::with_dummy_span(sym::cfg_select), ); } else { - // Emit a compiler error when none of the rules matched. + // Emit a compiler error when none of the predicates matched. let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp }); DummyResult::any(sp, guar) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 8c3093acea45..c55a9e73e382 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> { match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None), Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 506286fc2559..313bf6d20a66 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -879,9 +879,7 @@ pub(crate) fn codegen( .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); let thin_bc = module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); - unsafe { - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); - } + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); } } @@ -945,7 +943,7 @@ pub(crate) fn codegen( // binaries. So we must clone the module to produce the asm output // if we are also producing object code. let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { - unsafe { llvm::LLVMCloneModule(llmod) } + llvm::LLVMCloneModule(llmod) } else { llmod }; @@ -1073,7 +1071,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> } /// Embed the bitcode of an LLVM module for LTO in the LLVM module itself. -unsafe fn embed_bitcode( +fn embed_bitcode( cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module, @@ -1115,43 +1113,40 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - unsafe { - if cgcx.target_is_like_darwin - || cgcx.target_is_like_aix - || cgcx.target_arch == "wasm32" - || cgcx.target_arch == "wasm64" - { - // We don't need custom section flags, create LLVM globals. - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); - llvm::set_initializer(llglobal, llconst); - llvm::set_section(llglobal, bitcode_section_name(cgcx)); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + if cgcx.target_is_like_darwin + || cgcx.target_is_like_aix + || cgcx.target_arch == "wasm32" + || cgcx.target_arch == "wasm64" + { + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); + llvm::set_initializer(llglobal, llconst); - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); - llvm::set_initializer(llglobal, llconst); - let section = if cgcx.target_is_like_darwin { - c"__LLVM,__cmdline" - } else if cgcx.target_is_like_aix { - c".info" - } else { - c".llvmcmd" - }; - llvm::set_section(llglobal, section); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_section(llglobal, bitcode_section_name(cgcx)); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); + llvm::set_initializer(llglobal, llconst); + let section = if cgcx.target_is_like_darwin { + c"__LLVM,__cmdline" + } else if cgcx.target_is_like_aix { + c".info" } else { - // We need custom section flags, so emit module-level inline assembly. - let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; - let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::append_module_inline_asm(llmod, &asm); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::append_module_inline_asm(llmod, &asm); - } + c".llvmcmd" + }; + llvm::set_section(llglobal, section); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + } else { + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::append_module_inline_asm(llmod, &asm); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + llvm::append_module_inline_asm(llmod, &asm); } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9c3b866aa3c6..514923ad6f37 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -302,10 +302,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - let id_str = "branch_weights"; - let id = unsafe { - llvm::LLVMMDStringInContext2(self.cx.llcx, id_str.as_ptr().cast(), id_str.len()) - }; + let id = self.cx.create_metadata(b"branch_weights"); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to @@ -637,17 +634,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } else if place.layout.is_llvm_immediate() { let mut const_llval = None; let llty = place.layout.llvm_type(self); - unsafe { - if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { - if llvm::LLVMIsGlobalConstant(global) == llvm::True { - if let Some(init) = llvm::LLVMGetInitializer(global) { - if self.val_ty(init) == llty { - const_llval = Some(init); - } + if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { + if llvm::LLVMIsGlobalConstant(global) == llvm::True { + if let Some(init) = llvm::LLVMGetInitializer(global) { + if self.val_ty(init) == llty { + const_llval = Some(init); } } } } + let llval = const_llval.unwrap_or_else(|| { let load = self.load(llty, place.val.llval, place.val.align); if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { @@ -1721,7 +1717,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.cx.create_metadata(typeid.as_bytes()); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 5afb9a60d424..dff684728473 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); + let enzyme_const = cx.create_metadata(b"enzyme_const"); + let enzyme_out = cx.create_metadata(b"enzyme_out"); + let enzyme_dup = cx.create_metadata(b"enzyme_dup"); + let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); + let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); + let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); + let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); + let enzyme_width = cx.create_metadata(b"enzyme_width"); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b9b5c776d86a..f9ab96b57895 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -215,10 +215,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { bug!("symbol `{}` is already defined", sym); }); llvm::set_initializer(g, sc); - unsafe { - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - } + + llvm::set_global_constant(g, true); + llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); // Cast to default address space if globals are in a different addrspace let g = self.const_pointercast(g, self.type_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5deddb3ed981..0b96b63bc857 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -17,13 +17,12 @@ use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; -use crate::common::{AsCCharPtr, CodegenCx}; +use crate::common::CodegenCx; use crate::errors::SymbolAlreadyDefined; -use crate::llvm::{self, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use crate::{base, debuginfo}; +use crate::{base, debuginfo, llvm}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, @@ -247,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> { }; llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); - llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global); gv } @@ -272,9 +271,8 @@ impl<'ll> CodegenCx<'ll, '_> { return gv; } let gv = self.static_addr_of_mut(cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } + llvm::set_global_constant(gv, true); + self.const_globals.borrow_mut().insert(cv, gv); gv } @@ -398,149 +396,140 @@ impl<'ll> CodegenCx<'ll, '_> { } fn codegen_static_item(&mut self, def_id: DefId) { - unsafe { - assert!( - llvm::LLVMGetInitializer( - self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() - ) - .is_none() - ); - let attrs = self.tcx.codegen_fn_attrs(def_id); + assert!( + llvm::LLVMGetInitializer( + self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() + ) + .is_none() + ); + let attrs = self.tcx.codegen_fn_attrs(def_id); - let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { - // Error has already been reported - return; - }; - let alloc = alloc.inner(); + let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { + // Error has already been reported + return; + }; + let alloc = alloc.inner(); - let val_llty = self.val_ty(v); + let val_llty = self.val_ty(v); - let g = self.get_static_inner(def_id, val_llty); - let llty = self.get_type_of_global(g); + let g = self.get_static_inner(def_id, val_llty); + let llty = self.get_type_of_global(g); - let g = if val_llty == llty { - g - } else { - // codegen_static_initializer creates the global value just from the - // `Allocation` data by generating one big struct value that is just - // all the bytes and pointers after each other. This will almost never - // match the type that the static was declared with. Unfortunately - // we can't just LLVMConstBitCast our way out of it because that has very - // specific rules on what can be cast. So instead of adding a new way to - // generate static initializers that match the static's type, we picked - // the easier option and retroactively change the type of the static item itself. - let name = llvm::get_value_name(g); - llvm::set_value_name(g, b""); + let g = if val_llty == llty { + g + } else { + // codegen_static_initializer creates the global value just from the + // `Allocation` data by generating one big struct value that is just + // all the bytes and pointers after each other. This will almost never + // match the type that the static was declared with. Unfortunately + // we can't just LLVMConstBitCast our way out of it because that has very + // specific rules on what can be cast. So instead of adding a new way to + // generate static initializers that match the static's type, we picked + // the easier option and retroactively change the type of the static item itself. + let name = String::from_utf8(llvm::get_value_name(g)) + .expect("we declare our statics with a utf8-valid name"); + llvm::set_value_name(g, b""); - let linkage = llvm::get_linkage(g); - let visibility = llvm::get_visibility(g); + let linkage = llvm::get_linkage(g); + let visibility = llvm::get_visibility(g); - let new_g = llvm::LLVMRustGetOrInsertGlobal( - self.llmod, - name.as_c_char_ptr(), - name.len(), - val_llty, - ); + let new_g = self.declare_global(&name, val_llty); - llvm::set_linkage(new_g, linkage); - llvm::set_visibility(new_g, visibility); + llvm::set_linkage(new_g, linkage); + llvm::set_visibility(new_g, visibility); - // The old global has had its name removed but is returned by - // get_static since it is in the instance cache. Provide an - // alternative lookup that points to the new global so that - // global_asm! can compute the correct mangled symbol name - // for the global. - self.renamed_statics.borrow_mut().insert(def_id, new_g); + // The old global has had its name removed but is returned by + // get_static since it is in the instance cache. Provide an + // alternative lookup that points to the new global so that + // global_asm! can compute the correct mangled symbol name + // for the global. + self.renamed_statics.borrow_mut().insert(def_id, new_g); - // To avoid breaking any invariants, we leave around the old - // global for the moment; we'll replace all references to it - // with the new global later. (See base::codegen_backend.) - self.statics_to_rauw.borrow_mut().push((g, new_g)); - new_g - }; - set_global_alignment(self, g, alloc.align); - llvm::set_initializer(g, v); + // To avoid breaking any invariants, we leave around the old + // global for the moment; we'll replace all references to it + // with the new global later. (See base::codegen_backend.) + self.statics_to_rauw.borrow_mut().push((g, new_g)); + new_g + }; + set_global_alignment(self, g, alloc.align); + llvm::set_initializer(g, v); - self.assume_dso_local(g, true); + self.assume_dso_local(g, true); - // Forward the allocation's mutability (picked by the const interner) to LLVM. - if alloc.mutability.is_not() { - llvm::LLVMSetGlobalConstant(g, llvm::True); - } + // Forward the allocation's mutability (picked by the const interner) to LLVM. + if alloc.mutability.is_not() { + llvm::set_global_constant(g, true); + } - debuginfo::build_global_var_di_node(self, def_id, g); + debuginfo::build_global_var_di_node(self, def_id, g); - if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { - llvm::set_thread_local_mode(g, self.tls_model); - } + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + llvm::set_thread_local_mode(g, self.tls_model); + } - // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. The exception to this - // is the `.init_array` section which are treated specially by the wasm linker. - if self.tcx.sess.target.is_like_wasm - && attrs - .link_section - .map(|link_section| !link_section.as_str().starts_with(".init_array")) - .unwrap_or(true) - { - if let Some(section) = attrs.link_section { - let section = llvm::LLVMMDStringInContext2( - self.llcx, - section.as_str().as_c_char_ptr(), - section.as_str().len(), - ); - assert!(alloc.provenance().ptrs().is_empty()); + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { + if let Some(section) = attrs.link_section { + let section = self.create_metadata(section.as_str().as_bytes()); + assert!(alloc.provenance().ptrs().is_empty()); - // The `inspect` method is okay here because we checked for provenance, and - // because we are doing this access to inspect the final interpreter state (not - // as part of the interpreter execution). - let bytes = - alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); - let data = [section, alloc]; - let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = self.get_metadata_value(meta); + // The `inspect` method is okay here because we checked for provenance, and + // because we are doing this access to inspect the final interpreter state (not + // as part of the interpreter execution). + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); + let alloc = self.create_metadata(bytes); + let data = [section, alloc]; + let meta = + unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; + let val = self.get_metadata_value(meta); + unsafe { llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), val, - ); - } - } else { - base::set_link_section(g, attrs); + ) + }; } + } else { + base::set_link_section(g, attrs); + } - base::set_variable_sanitizer_attrs(g, attrs); + base::set_variable_sanitizer_attrs(g, attrs); - if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); - // The semantics of #[used] in Rust only require the symbol to make it into the - // object file. It is explicitly allowed for the linker to strip the symbol if it - // is dead, which means we are allowed to use `llvm.compiler.used` instead of - // `llvm.used` here. - // - // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique - // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs - // in the handling of `.init_array` (the static constructor list) in versions of - // the gold linker (prior to the one released with binutils 2.36). - // - // That said, we only ever emit these when `#[used(compiler)]` is explicitly - // requested. This is to avoid similar breakage on other targets, in particular - // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` - // is emitted rather than `llvm.used`. However, that check happens when assigning - // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to - // take care of it here. - self.add_compiler_used_global(g); - } - if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); + // The semantics of #[used] in Rust only require the symbol to make it into the + // object file. It is explicitly allowed for the linker to strip the symbol if it + // is dead, which means we are allowed to use `llvm.compiler.used` instead of + // `llvm.used` here. + // + // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique + // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs + // in the handling of `.init_array` (the static constructor list) in versions of + // the gold linker (prior to the one released with binutils 2.36). + // + // That said, we only ever emit these when `#[used(compiler)]` is explicitly + // requested. This is to avoid similar breakage on other targets, in particular + // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` + // is emitted rather than `llvm.used`. However, that check happens when assigning + // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to + // take care of it here. + self.add_compiler_used_global(g); + } + if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); - self.add_used_global(g); - } + self.add_used_global(g); } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 90582e23b04c..6a23becaa96f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,6 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm::Metadata; use crate::type_::Type; @@ -169,6 +168,8 @@ pub(crate) unsafe fn create_module<'ll>( let mod_name = SmallCStr::new(mod_name); let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; + let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()); + let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); @@ -473,18 +474,14 @@ pub(crate) unsafe fn create_module<'ll>( #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = unsafe { - llvm::LLVMMDStringInContext2( - llcx, - rustc_producer.as_c_char_ptr(), - rustc_producer.as_bytes().len(), - ) - }; + + let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); + unsafe { llvm::LLVMAddNamedMetadataOperand( llmod, c"llvm.ident".as_ptr(), - &llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), + &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), ); } @@ -698,10 +695,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { - Some(unsafe { + pub(crate) fn create_metadata(&self, name: &[u8]) -> &'ll Metadata { + unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) - }) + } } pub(crate) fn get_functions(&self) -> Vec<&'ll Value> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 49ee96a41d69..61555ac2f6f6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -74,7 +74,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::set_initializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); - llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9b4736e50e6c..0e9dbfba658d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{iter, ptr}; -use libc::{c_char, c_longlong, c_uint}; +use libc::{c_longlong, c_uint}; use rustc_abi::{Align, Size}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; @@ -1582,13 +1582,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); + let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); unsafe { - let typeid = llvm::LLVMMDStringInContext2( - cx.llcx, - trait_ref_typeid.as_ptr() as *const c_char, - trait_ref_typeid.as_bytes().len(), - ); let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; llvm::LLVMRustGlobalAddMetadata( vtable, @@ -1630,7 +1626,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( // When full debuginfo is enabled, we want to try and prevent vtables from being // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. - llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No); + llvm::set_unnamed_address(vtable, llvm::UnnamedAddr::No); let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 2419ec1f8885..eb75716d768b 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -49,7 +49,7 @@ pub(crate) fn declare_simple_fn<'ll>( }; llvm::SetFunctionCallConv(llfn, callconv); - llvm::SetUnnamedAddress(llfn, unnamed); + llvm::set_unnamed_address(llfn, unnamed); llvm::set_visibility(llfn, visibility); llfn @@ -176,7 +176,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { { let typeid = cfi::typeid_for_instance(self.tcx, instance, options); if typeids.insert(typeid.clone()) { - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } else { @@ -189,7 +189,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { .map(cfi::TypeIdOptions::from_iter) { let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 5c34ab2e3040..0b1e632cbc42 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1009,7 +1009,7 @@ unsafe extern "C" { ModuleID: *const c_char, C: &Context, ) -> &Module; - pub(crate) fn LLVMCloneModule(M: &Module) -> &Module; + pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; /// Data layout. See Module::getDataLayout. pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char; @@ -1168,18 +1168,18 @@ unsafe extern "C" { pub(crate) fn LLVMGlobalGetValueType(Global: &Value) -> &Type; // Operations on global variables - pub(crate) fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>; pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>; pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMDeleteGlobal(GlobalVar: &Value); - pub(crate) fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value); - pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); - pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; - pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); + pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes @@ -1718,7 +1718,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; - pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); + pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); pub(crate) fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 3fc83fca352a..154ba4fd6901 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -217,10 +217,8 @@ pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) { set_comdat(llmod, val, &name); } -pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) { - unsafe { - LLVMSetUnnamedAddress(global, unnamed); - } +pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) { + LLVMSetUnnamedAddress(global, unnamed); } pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) { @@ -260,9 +258,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { } pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) { - unsafe { - LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); - } + LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); } pub(crate) fn get_linkage(llglobal: &Value) -> Linkage { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191bf..8f70270f203e 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -131,8 +131,8 @@ impl CodegenCx<'_, '_> { } // Thread-local variables generally don't support copy relocations. - let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) } - .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True); + let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) + .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); if is_thread_local_var { return false; } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ee472e75ed41..893655031388 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use std::hash::{Hash, Hasher}; use std::{fmt, ptr}; -use libc::{c_char, c_uint}; +use libc::c_uint; use rustc_abi::{AddressSpace, Align, Integer, Reg, Size}; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -298,8 +298,8 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn add_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMRustGlobalAddMetadata( @@ -310,8 +310,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn set_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMGlobalSetMetadata( @@ -322,10 +322,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { - Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len()) - }) + fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { + Some(self.create_metadata(typeid)) } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 2aa5c3c27ea5..34ad35a729b9 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -139,7 +139,8 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( && bx.cx().sess().lto() == Lto::Fat { if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { - let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); + let typeid = + bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap(); let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); return func; } else if nonnull { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index dcd9e25b2c95..32c24965e1bf 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -154,9 +154,9 @@ pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes { // For backends that support CFI using type membership (i.e., testing whether a given pointer is // associated with a type identifier). pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes { - fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn typeid_metadata(&self, _typeid: String) -> Option { + fn add_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn set_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn typeid_metadata(&self, _typeid: &[u8]) -> Option { None } fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index b767ca9a3c25..c9b7356432da 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -296,19 +296,22 @@ const_eval_pointer_arithmetic_overflow = overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` const_eval_pointer_out_of_bounds = - {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg -> - [false] {$alloc_size_minus_ptr_offset -> - [0] is at or beyond the end of the allocation of size {$alloc_size -> - [1] 1 byte - *[x] {$alloc_size} bytes + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg -> + [true] points to before the beginning of the allocation + *[false] {$inbounds_size_is_neg -> + [false] {$alloc_size_minus_ptr_offset -> + [0] is at or beyond the end of the allocation of size {$alloc_size -> + [1] 1 byte + *[x] {$alloc_size} bytes + } + [1] is only 1 byte from the end of the allocation + *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + } + *[true] {$ptr_offset_abs -> + [0] is at the beginning of the allocation + *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation } - [1] is only 1 byte from the end of the allocation - *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation - } - *[true] {$ptr_offset_abs -> - [0] is at the beginning of the allocation - *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation - } + } } const_eval_pointer_use_after_free = diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index ad3e02580f33..1503f3bcd990 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout}; +use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 41fc8d47cd36..11e7706fe605 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ - self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, - TyAndLayout, + self, FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, + LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; use rustc_middle::{mir, span_bug}; @@ -92,20 +92,6 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } } -impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { - /// This inherent method takes priority over the trait method with the same name in LayoutOf, - /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. - /// See [LayoutOf::layout_of] for the original documentation. - #[inline(always)] - pub fn layout_of( - &self, - ty: Ty<'tcx>, - ) -> as LayoutOfHelpers<'tcx>>::LayoutOfResult { - let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind()); - LayoutOf::layout_of(self, ty) - } -} - impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>; @@ -121,6 +107,43 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { } } +impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// This inherent method takes priority over the trait method with the same name in LayoutOf, + /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. + /// See [LayoutOf::layout_of] for the original documentation. + #[inline(always)] + pub fn layout_of(&self, ty: Ty<'tcx>) -> >::LayoutOfResult { + let _span = enter_trace_span!(M, "InterpCx::layout_of", ty = ?ty.kind()); + LayoutOf::layout_of(self, ty) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_fn_ptr] with a tracing span. + /// See [FnAbiOf::fn_abi_of_fn_ptr] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_fn_ptr( + &self, + sig: ty::PolyFnSig<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_fn_ptr", ?sig, ?extra_args); + FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance] with a tracing span. + /// See [FnAbiOf::fn_abi_of_instance] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_instance( + &self, + instance: ty::Instance<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_instance", ?instance, ?extra_args); + FnAbiOf::fn_abi_of_instance(self, instance, extra_args) + } +} + /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 1eba1f2f03c9..22d29eda913a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -44,17 +44,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; self.copy_op_allow_transmute(&op, dest)?; - // Give the first pointer-size bytes provenance that knows about the type id. + // Give the each pointer-sized chunk provenance that knows about the type id. // Here we rely on `TypeId` being a newtype around an array of pointers, so we - // first project to its only field and then the first array element. + // first project to its only field and then the array elements. let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); let first = self.project_field(dest, FieldIdx::ZERO)?; - let first = self.project_index(&first, 0)?; - let offset = self.read_scalar(&first)?.to_target_usize(&tcx)?; - let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset)); - let ptr = self.global_root_pointer(ptr)?; - let val = Scalar::from_pointer(ptr, &tcx); - self.write_scalar(val, &first) + let mut elem_iter = self.project_array_fields(&first)?; + while let Some((_, elem)) = elem_iter.next(self)? { + // Decorate this part of the hash with provenance; leave the integer part unchanged. + let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?; + let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(hash_fragment)); + let ptr = self.global_root_pointer(ptr)?; + let val = Scalar::from_pointer(ptr, &tcx); + self.write_scalar(val, &elem)?; + } + interp_ok(()) } /// Returns `true` if emulation happened. @@ -101,34 +105,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let mut a_fields = self.project_array_fields(&a_fields)?; let mut b_fields = self.project_array_fields(&b_fields)?; - let (_idx, a) = a_fields - .next(self)? - .expect("we know the layout of TypeId has at least 2 array elements"); - let a = self.deref_pointer(&a)?; - let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; + let mut provenance_a = None; + let mut provenance_b = None; + let mut provenance_matches = true; - let (_idx, b) = b_fields - .next(self)? - .expect("we know the layout of TypeId has at least 2 array elements"); - let b = self.deref_pointer(&b)?; - let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; - - let provenance_matches = a == b; - - let mut eq_id = offset_a == offset_b; - - while let Some((_, a)) = a_fields.next(self)? { + while let Some((i, a)) = a_fields.next(self)? { let (_, b) = b_fields.next(self)?.unwrap(); - let a = self.read_target_usize(&a)?; - let b = self.read_target_usize(&b)?; - eq_id &= a == b; - } + let a = self.deref_pointer(&a)?; + let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; - if !eq_id && provenance_matches { - throw_ub_format!( - "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents" - ) + let b = self.deref_pointer(&b)?; + let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; + + if *provenance_a.get_or_insert(a) != a { + throw_ub_format!( + "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" + ) + } + if *provenance_b.get_or_insert(b) != b { + throw_ub_format!( + "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" + ) + } + provenance_matches &= a == b; + + if offset_a != offset_b && provenance_matches { + throw_ub_format!( + "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents" + ) + } } self.write_scalar(Scalar::from_bool(provenance_matches), dest)?; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 833fcc388179..629dcc3523ca 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -5,7 +5,6 @@ use either::Either; use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_index::IndexSlice; -use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_error_codes/src/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md index c081a3d9cfa8..f00d17739448 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0536.md +++ b/compiler/rustc_error_codes/src/error_codes/E0536.md @@ -3,22 +3,20 @@ The `not` cfg-predicate was malformed. Erroneous code example: ```compile_fail,E0536 -#[cfg(not())] // error: expected 1 cfg-pattern -pub fn something() {} - -pub fn main() {} +pub fn main() { + if cfg!(not()) { } +} ``` The `not` predicate expects one cfg-pattern. Example: ``` -#[cfg(not(target_os = "linux"))] // ok! -pub fn something() {} - -pub fn main() {} +pub fn main() { + if cfg!(not(target_os = "linux")) { } // ok! +} ``` -For more information about the `cfg` attribute, read the section on +For more information about the `cfg` macro, read the section on [Conditional Compilation][conditional-compilation] in the Reference. [conditional-compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 757a7e1c8e77..ce3006c2604a 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -11,7 +11,7 @@ use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; -use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr}; +use rustc_attr_data_structures::{AttributeKind, CfgEntry, Deprecation, Stability, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; @@ -1128,7 +1128,13 @@ pub trait ResolverExpand { /// HIR proc macros items back to their harness items. fn declare_proc_macro(&mut self, id: NodeId); - fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem); + fn append_stripped_cfg_item( + &mut self, + parent_node: NodeId, + ident: Ident, + cfg: CfgEntry, + cfg_span: Span, + ); /// Tools registered with `#![register_tool]` and used by tool attributes and lints. fn registered_tools(&self) -> &RegisteredTools; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 170ac39d1ec3..6922ddfd6bdd 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -11,6 +11,9 @@ use rustc_ast::{ NodeId, NormalAttr, }; use rustc_attr_parsing as attr; +use rustc_attr_parsing::{ + AttributeParser, CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr, +}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features, @@ -18,6 +21,7 @@ use rustc_feature::{ }; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; +use rustc_parse::validate_attr::deny_builtin_meta_unsafety; use rustc_session::Session; use rustc_session::parse::feature_err; use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; @@ -161,7 +165,10 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec attrs .iter() .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)) - .take_while(|attr| !is_cfg(attr) || strip_unconfigured.cfg_true(attr).0) + .take_while(|attr| { + !is_cfg(attr) + || strip_unconfigured.cfg_true(attr, strip_unconfigured.lint_node_id).as_bool() + }) .collect() } @@ -394,26 +401,42 @@ impl<'a> StripUnconfigured<'a> { /// Determines if a node with the given attributes should be included in this configuration. fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr).0) + attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr, self.lint_node_id).as_bool()) } - pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option) { - let meta_item = match validate_attr::parse_meta(&self.sess.psess, attr) { - Ok(meta_item) => meta_item, + pub(crate) fn cfg_true(&self, attr: &Attribute, node: NodeId) -> EvalConfigResult { + // We need to run this to do basic validation of the attribute, such as that lits are valid, etc + // FIXME(jdonszelmann) this should not be necessary in the future + match validate_attr::parse_meta(&self.sess.psess, attr) { + Ok(_) => {} Err(err) => { err.emit(); - return (true, None); + return EvalConfigResult::True; } + } + + // Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check + deny_builtin_meta_unsafety( + self.sess.dcx(), + attr.get_normal_item().unsafety, + &rustc_ast::Path::from_ident(attr.ident().unwrap()), + ); + + let Some(cfg) = AttributeParser::parse_single( + self.sess, + attr, + attr.span, + node, + self.features, + true, + parse_cfg_attr, + &CFG_TEMPLATE, + ) else { + // Cfg attribute was not parsable, give up + return EvalConfigResult::True; }; - validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item); - - ( - parse_cfg(&meta_item, self.sess).is_none_or(|meta_item| { - attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features) - }), - Some(meta_item), - ) + eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features) } /// If attributes are not allowed on expressions, emit an error for `attr` @@ -465,6 +488,7 @@ impl<'a> StripUnconfigured<'a> { } } +/// FIXME: Still used by Rustdoc, should be removed after pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> { let span = meta_item.span; match meta_item.meta_item_list() { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 2de09aa1a280..f99060e9a216 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,6 +13,7 @@ use rustc_ast::{ MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; +use rustc_attr_parsing::EvalConfigResult; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::PResult; use rustc_feature::Features; @@ -2166,19 +2167,19 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn expand_cfg_true( &mut self, - node: &mut impl HasAttrs, + node: &mut (impl HasAttrs + HasNodeId), attr: ast::Attribute, pos: usize, - ) -> (bool, Option) { - let (res, meta_item) = self.cfg().cfg_true(&attr); - if res { + ) -> EvalConfigResult { + let res = self.cfg().cfg_true(&attr, node.node_id()); + if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. let trace_attr = attr_into_trace(attr, sym::cfg_trace); node.visit_attrs(|attrs| attrs.insert(pos, trace_attr)); } - (res, meta_item) + res } fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) { @@ -2199,20 +2200,21 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { return match self.take_first_attr(&mut node) { Some((attr, pos, derives)) => match attr.name() { Some(sym::cfg) => { - let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos); - if res { - continue; - } - - if let Some(meta_item) = meta_item { - for ident in node.declared_idents() { - self.cx.resolver.append_stripped_cfg_item( - self.cx.current_expansion.lint_node_id, - ident, - meta_item.clone(), - ) + let res = self.expand_cfg_true(&mut node, attr, pos); + match res { + EvalConfigResult::True => continue, + EvalConfigResult::False { reason, reason_span } => { + for ident in node.declared_idents() { + self.cx.resolver.append_stripped_cfg_item( + self.cx.current_expansion.lint_node_id, + ident, + reason.clone(), + reason_span, + ) + } } } + Default::default() } Some(sym::cfg_attr) => { @@ -2291,7 +2293,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Some((attr, pos, derives)) => match attr.name() { Some(sym::cfg) => { let span = attr.span; - if self.expand_cfg_true(node, attr, pos).0 { + if self.expand_cfg_true(node, attr, pos).as_bool() { continue; } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index df010f870982..ca57c4f31641 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -295,6 +295,12 @@ impl DefKind { } } + /// This is a "module" in name resolution sense. + #[inline] + pub fn is_module_like(self) -> bool { + matches!(self, DefKind::Mod | DefKind::Enum | DefKind::Trait) + } + #[inline] pub fn is_fn_like(self) -> bool { matches!( @@ -720,6 +726,15 @@ impl Res { } } + /// If this is a "module" in name resolution sense, return its `DefId`. + #[inline] + pub fn module_like_def_id(&self) -> Option { + match self { + Res::Def(def_kind, def_id) if def_kind.is_module_like() => Some(*def_id), + _ => None, + } + } + /// A human readable name for the res kind ("function", "module", etc.). pub fn descr(&self) -> &'static str { match *self { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index cb106962be18..364ad38556be 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -49,7 +49,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } = self.lower_poly_trait_ref( &trait_bound.trait_ref, trait_bound.span, - hir::BoundConstness::Never, + trait_bound.modifiers.constness, hir::BoundPolarity::Positive, dummy_self, &mut user_written_bounds, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index bc9badbb232e..db89396d1dc2 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -167,7 +167,7 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, None), Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 19954459cb59..57a672c45f7b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -3,7 +3,7 @@ use std::mem; use std::sync::Arc; use rustc_attr_data_structures::Deprecation; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; @@ -510,10 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } Entry::Vacant(entry) => { entry.insert(parent); - if matches!( - child.res, - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _) - ) { + if child.res.module_like_def_id().is_some() { bfs_queue.push_back(def_id); } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8347626080e6..915c97316880 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -7,7 +7,7 @@ use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; -use rustc_ast::expand::StrippedCfgItem; +use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_hir::PreciseCapturingArgKind; diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index f140ab4755bd..43a7af9ce380 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -110,7 +110,7 @@ macro_rules! arena_types { [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, - [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, + [] stripped_cfg_items: rustc_attr_data_structures::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, [] features: rustc_feature::Features, [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 842d118449a5..935cc8895740 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -69,8 +69,8 @@ use std::sync::Arc; use rustc_abi::Align; use rustc_arena::TypedArena; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::allocator::AllocatorKind; +use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a352ab3fd08a..6e8f1e8fdd5b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -25,10 +25,9 @@ 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::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; -use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_attr_data_structures::{AttributeKind, StrippedCfgItem, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 3d601fc05338..dbacbe21edb7 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -87,7 +87,7 @@ trivially_parameterized_over_tcx! { ty::IntrinsicDef, rustc_ast::Attribute, rustc_ast::DelimArgs, - rustc_ast::expand::StrippedCfgItem, + rustc_attr_data_structures::StrippedCfgItem, rustc_attr_data_structures::ConstStability, rustc_attr_data_structures::DefaultBodyStability, rustc_attr_data_structures::Deprecation, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7c48a4b0885e..8f0f9b21dc16 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3454,9 +3454,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N collect_fn(&child.ident, ns, def_id); } - if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait) - && seen_defs.insert(def_id) - { + if defkind.is_module_like() && seen_defs.insert(def_id) { queue.push(def_id); } } diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index 24a05afff4ac..2c6fb224d70d 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use crate::exp; use crate::parser::Parser; -pub enum CfgSelectRule { +pub enum CfgSelectPredicate { Cfg(MetaItemInner), Wildcard(Token), } @@ -20,7 +20,7 @@ pub struct CfgSelectBranches { pub wildcard: Option<(Token, TokenStream, Span)>, /// All branches after the first wildcard, including further wildcards. /// These branches are kept for formatting. - pub unreachable: Vec<(CfgSelectRule, TokenStream, Span)>, + pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, } /// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where @@ -52,7 +52,7 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.wildcard = Some((underscore, tts, span)), Some(_) => { - branches.unreachable.push((CfgSelectRule::Wildcard(underscore), tts, span)) + branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span)) } } } else { @@ -64,7 +64,9 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.reachable.push((meta_item, tts, span)), - Some(_) => branches.unreachable.push((CfgSelectRule::Cfg(meta_item), tts, span)), + Some(_) => { + branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span)) + } } } } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a997be3405d6..740dd10ea8ba 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -575,14 +575,69 @@ impl<'a> Parser<'a> { self.expect(exp!(CloseBracket))?; } TyKind::Array(elt_ty, length) - } else { - self.expect(exp!(CloseBracket))?; + } else if self.eat(exp!(CloseBracket)) { TyKind::Slice(elt_ty) + } else { + self.maybe_recover_array_ty_without_semi(elt_ty)? }; Ok(ty) } + /// Recover from malformed array type syntax. + /// + /// This method attempts to recover from cases like: + /// - `[u8, 5]` → suggests using `;`, return a Array type + /// - `[u8 5]` → suggests using `;`, return a Array type + /// Consider to add more cases in the future. + fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: P) -> PResult<'a, TyKind> { + let span = self.token.span; + let token_descr = super::token_descr(&self.token); + let mut err = + self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr)); + err.span_label(span, "expected `;` or `]`"); + err.note("you might have meant to write a slice or array type"); + + // If we cannot recover, return the error immediately. + if !self.may_recover() { + return Err(err); + } + + let snapshot = self.create_snapshot_for_diagnostic(); + + let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) { + // Consume common erroneous separators. + self.prev_token.span + } else { + self.token.span.shrink_to_lo() + }; + + // we first try to parse pattern like `[u8 5]` + let length = match self.parse_expr_anon_const() { + Ok(length) => length, + Err(e) => { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + }; + + if let Err(e) = self.expect(exp!(CloseBracket)) { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + + err.span_suggestion_verbose( + suggestion_span, + "you might have meant to use `;` as the separator", + ";", + Applicability::MaybeIncorrect, + ); + err.emit(); + Ok(TyKind::Array(elt_ty, length)) + } + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let and_span = self.prev_token.span; let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime()); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 5c748e956a06..783d79d978ab 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -4,9 +4,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, - Safety, + Path, Safety, }; -use rustc_errors::{Applicability, FatalError, PResult}; +use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; @@ -247,14 +247,12 @@ pub fn check_attribute_safety( // Called by `check_builtin_meta_item` and code that manually denies // `unsafe(...)` in `cfg` -pub fn deny_builtin_meta_unsafety(psess: &ParseSess, meta: &MetaItem) { +pub fn deny_builtin_meta_unsafety(diag: DiagCtxtHandle<'_>, unsafety: Safety, name: &Path) { // This only supports denying unsafety right now - making builtin attributes // support unsafety will requite us to thread the actual `Attribute` through // for the nice diagnostics. - if let Safety::Unsafe(unsafe_span) = meta.unsafety { - psess - .dcx() - .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() }); + if let Safety::Unsafe(unsafe_span) = unsafety { + diag.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: name.clone() }); } } @@ -299,6 +297,7 @@ pub fn check_builtin_meta_item( | sym::align | sym::deprecated | sym::optimize + | sym::pointee | sym::cold | sym::target_feature | sym::rustc_allow_const_fn_unstable @@ -326,7 +325,7 @@ pub fn check_builtin_meta_item( } if deny_unsafety { - deny_builtin_meta_unsafety(psess, meta); + deny_builtin_meta_unsafety(psess.dcx(), meta.unsafety, &meta.path); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 820255afe274..2009ddc1e2d5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -251,6 +251,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) + | AttributeKind::Pointee(..) | AttributeKind::Dummy | AttributeKind::OmitGdbPrettyPrinterSection, ) => { /* do nothing */ } @@ -381,7 +382,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfg_attr_trace // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) - | sym::pointee // FIXME(derive_coerce_pointee) | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6979d89a8e7b..5a1be618ceea 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -20,9 +20,9 @@ use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; +use rustc_middle::bug; use rustc_middle::metadata::ModChild; -use rustc_middle::ty::Feed; -use rustc_middle::{bug, ty}; +use rustc_middle::ty::{Feed, Visibility}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use tracing::debug; @@ -33,54 +33,42 @@ use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::{ BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError, errors, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, + VisResolutionError, errors, }; type Res = def::Res; -impl<'ra, Id: Into> ToNameBinding<'ra> - for (Module<'ra>, ty::Visibility, Span, LocalExpnId) -{ - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Module(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - -impl<'ra, Id: Into> ToNameBinding<'ra> for (Res, ty::Visibility, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. - pub(crate) fn define(&mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, def: T) - where - T: ToNameBinding<'ra>, - { - let binding = def.to_name_binding(self.arenas); + pub(crate) fn define_binding( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + binding: NameBinding<'ra>, + ) { let key = self.new_disambiguated_key(ident, ns); if let Err(old_binding) = self.try_define(parent, key, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } + fn define( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + res: Res, + vis: Visibility>, + span: Span, + expn_id: LocalExpnId, + ) { + let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id); + self.define_binding(parent, ident, ns, binding) + } + /// Walks up the tree of definitions starting at `def_id`, /// stopping at the first encountered module. /// Parent block modules for arbitrary def-ids are not recorded for the local crate, @@ -121,7 +109,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !def_id.is_local() { // Query `def_kind` is not used because query system overhead is too expensive here. let def_kind = self.cstore().def_kind_untracked(def_id); - if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind { + if def_kind.is_module_like() { let parent = self .tcx .opt_parent(def_id) @@ -223,12 +211,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let expansion = parent_scope.expansion; // Record primary definitions. match res { - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => { - let module = self.expect_module(def_id); - self.define(parent, ident, TypeNS, (module, vis, span, expansion)); - } Res::Def( - DefKind::Struct + DefKind::Mod + | DefKind::Enum + | DefKind::Trait + | DefKind::Struct | DefKind::Union | DefKind::Variant | DefKind::TyAlias @@ -239,7 +226,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _, ) | Res::PrimTy(..) - | Res::ToolMod => self.define(parent, ident, TypeNS, (res, vis, span, expansion)), + | Res::ToolMod => self.define(parent, ident, TypeNS, res, vis, span, expansion), Res::Def( DefKind::Fn | DefKind::AssocFn @@ -248,9 +235,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | DefKind::AssocConst | DefKind::Ctor(..), _, - ) => self.define(parent, ident, ValueNS, (res, vis, span, expansion)), + ) => self.define(parent, ident, ValueNS, res, vis, span, expansion), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define(parent, ident, MacroNS, (res, vis, span, expansion)) + self.define(parent, ident, MacroNS, res, vis, span, expansion) } Res::Def( DefKind::TyParam @@ -294,10 +281,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { Res::Def(self.r.tcx.def_kind(def_id), def_id) } - fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { + fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility { self.try_resolve_visibility(vis, true).unwrap_or_else(|err| { self.r.report_vis_error(err); - ty::Visibility::Public + Visibility::Public }) } @@ -305,10 +292,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { &mut self, vis: &'ast ast::Visibility, finalize: bool, - ) -> Result> { + ) -> Result> { let parent_scope = &self.parent_scope; match vis.kind { - ast::VisibilityKind::Public => Ok(ty::Visibility::Public), + ast::VisibilityKind::Public => Ok(Visibility::Public), ast::VisibilityKind::Inherited => { Ok(match self.parent_scope.module.kind { // Any inherited visibility resolved directly inside an enum or trait @@ -318,7 +305,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.tcx.visibility(def_id).expect_local() } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted( + _ => Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), }) @@ -366,9 +353,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } if module.is_normal() { match res { - Res::Err => Ok(ty::Visibility::Public), + Res::Err => Ok(Visibility::Public), _ => { - let vis = ty::Visibility::Restricted(res.def_id()); + let vis = Visibility::Restricted(res.def_id()); if self.r.is_accessible_from(vis, parent_scope.module) { Ok(vis.expect_local()) } else { @@ -433,7 +420,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &ast::Item, root_span: Span, root_id: NodeId, - vis: ty::Visibility, + vis: Visibility, ) { let current_module = self.parent_scope.module; let import = self.r.arenas.alloc_import(ImportData { @@ -481,7 +468,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { list_stem: bool, // The whole `use` item item: &Item, - vis: ty::Visibility, + vis: Visibility, root_span: Span, ) { debug!( @@ -690,7 +677,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { true, // The whole `use` item item, - ty::Visibility::Restricted( + Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), root_span, @@ -706,7 +693,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ident: Ident, feed: Feed<'tcx, LocalDefId>, adt_res: Res, - adt_vis: ty::Visibility, + adt_vis: Visibility, adt_span: Span, ) { let parent_scope = &self.parent_scope; @@ -714,7 +701,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let expansion = parent_scope.expansion; // Define a name in the type namespace if it is not anonymous. - self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion)); + self.r.define(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion); self.r.feed_visibility(feed, adt_vis); let def_id = feed.key(); @@ -766,7 +753,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); + + if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { + self.r.mods_with_parse_errors.insert(def_id); + } + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -774,24 +766,16 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { parent.no_implicit_prelude || ast::attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - - if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { - self.r.mods_with_parse_errors.insert(def_id); - } - - // Descend into the module. - self.parent_scope.module = module; } // These items live in the value namespace. ItemKind::Const(box ConstItem { ident, .. }) | ItemKind::Delegation(box Delegation { ident, .. }) | ItemKind::Static(box StaticItem { ident, .. }) => { - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); } ItemKind::Fn(box Fn { ident, .. }) => { - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). @@ -800,19 +784,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // These items live in the type namespace. ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); } ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); + + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), item.span, parent.no_implicit_prelude, ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.parent_scope.module = module; } // These items live in both the type and value namespaces. @@ -834,7 +818,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let mut ctor_vis = if vis.is_public() && ast::attr::contains_name(&item.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -847,7 +831,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // constructor visibility should still be determined correctly. let field_vis = self .try_resolve_visibility(&field.vis, false) - .unwrap_or(ty::Visibility::Public); + .unwrap_or(Visibility::Public); if ctor_vis.is_at_least(field_vis, self.r.tcx) { ctor_vis = field_vis; } @@ -856,7 +840,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion); self.r.feed_visibility(feed, ctor_vis); // We need the field visibility spans also for the constructor for E0603. self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields()); @@ -896,7 +880,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &Item, ident: Ident, local_def_id: LocalDefId, - vis: ty::Visibility, + vis: Visibility, parent: Module<'ra>, ) { let sp = item.span; @@ -920,8 +904,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let vis = ty::Visibility::::Public; - let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_pub_res_binding(module.res().unwrap(), sp, expansion); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); @@ -978,7 +961,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } } - self.r.define(parent, ident, TypeNS, imported_binding); + self.r.define_binding(parent, ident, TypeNS, imported_binding); } /// Constructs the reduced graph for one foreign item. @@ -995,7 +978,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); - self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); self.r.feed_visibility(feed, vis); } @@ -1081,7 +1064,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { root_span: span, span, module_path: Vec::new(), - vis: ty::Visibility::Restricted(CRATE_DEF_ID), + vis: Visibility::Restricted(CRATE_DEF_ID), }) }; @@ -1231,11 +1214,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.macro_names.insert(ident); let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { - ty::Visibility::Public + Visibility::Public } else { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) }; - let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); self.r.set_binding_parent_module(binding, parent_scope.module); self.r.all_macro_rules.insert(ident.name); if is_macro_export { @@ -1254,7 +1237,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); - self.r.define(self.r.graph_root, ident, MacroNS, import_binding); + self.r.define_binding(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id); @@ -1275,14 +1258,14 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Visibilities must not be resolved non-speculatively twice // and we already resolved this one as a `fn` item visibility. ItemKind::Fn(..) => { - self.try_resolve_visibility(&item.vis, false).unwrap_or(ty::Visibility::Public) + self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public) } _ => self.resolve_visibility(&item.vis), }; if !vis.is_public() { self.insert_unused_macro(ident, def_id, item.id); } - self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); + self.r.define(module, ident, MacroNS, res, vis, span, expansion); self.r.feed_visibility(feed, vis); self.parent_scope.macro_rules } @@ -1418,7 +1401,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if ctxt == AssocCtxt::Trait { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; - self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { let impl_def_id = self.r.tcx.local_parent(local_def_id); let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns); @@ -1503,13 +1486,13 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(variant.id); let def_id = feed.key(); let vis = self.resolve_visibility(&variant.vis); - self.r.define(parent, ident, TypeNS, (self.res(def_id), vis, variant.span, expn_id)); + self.r.define(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id); self.r.feed_visibility(feed, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. let ctor_vis = if vis.is_public() && ast::attr::contains_name(&variant.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -1519,7 +1502,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); + self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id); self.r.feed_visibility(feed, ctor_vis); } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index e2caf632dd2d..781e2ce97040 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -132,6 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), + Early { emit_errors: false }, ); let attrs = parser.parse_attribute_list( &i.attrs, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b2f16fb1dfba..11e4a729ae23 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,11 +1,10 @@ -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{ - self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, -}; +use rustc_ast::{self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{self as attr, AttributeKind, Stability, find_attr}; +use rustc_attr_data_structures::{ + self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; @@ -233,12 +232,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - let old_kind = match (ns, old_binding.module()) { + let old_kind = match (ns, old_binding.res()) { (ValueNS, _) => "value", (MacroNS, _) => "macro", (TypeNS, _) if old_binding.is_extern_crate() => "extern crate", - (TypeNS, Some(module)) if module.is_normal() => "module", - (TypeNS, Some(module)) if module.is_trait() => "trait", + (TypeNS, Res::Def(DefKind::Mod, _)) => "module", + (TypeNS, Res::Def(DefKind::Trait, _)) => "trait", (TypeNS, _) => "type", }; @@ -1320,7 +1319,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // collect submodules to explore - if let Some(module) = name_binding.module() { + if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); @@ -1340,14 +1339,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !is_extern_crate_that_also_appears_in_prelude || alias_import { // add the module to the lookup - if seen_modules.insert(module.def_id()) { + if seen_modules.insert(def_id) { if via_import { &mut worklist_via_import } else { &mut worklist }.push( ( - module, + this.expect_module(def_id), path_segments, child_accessible, child_doc_visible, - is_stable && this.is_stable(module.def_id(), name_binding.span), + is_stable && this.is_stable(def_id, name_binding.span), ), ); } @@ -2095,7 +2094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, // re-export )); } - NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} + NameBindingKind::Res(_) => {} } let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); @@ -2307,25 +2306,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .ok() }; if let Some(binding) = binding { - let mut found = |what| { - msg = format!( - "expected {}, found {} `{}` in {}", - ns.descr(), - what, - ident, - parent - ) - }; - if binding.module().is_some() { - found("module") - } else { - match binding.res() { - // Avoid using TyCtxt::def_kind_descr in the resolver, because it - // indirectly *calls* the resolver, and would cause a query cycle. - Res::Def(kind, id) => found(kind.descr(id)), - _ => found(ns_to_try.descr()), - } - } + msg = format!( + "expected {}, found {} `{ident}` in {parent}", + ns.descr(), + binding.res().descr(), + ); }; } (msg, None) @@ -2860,17 +2845,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let note = errors::FoundItemConfigureOut { span: ident.span }; err.subdiagnostic(note); - if let MetaItemKind::List(nested) = &cfg.kind - && let MetaItemInner::MetaItem(meta_item) = &nested[0] - && let MetaItemKind::NameValue(feature_name) = &meta_item.kind - { - let note = errors::ItemWasBehindFeature { - feature: feature_name.symbol, - span: meta_item.span, - }; + if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { + let note = errors::ItemWasBehindFeature { feature, span: cfg.1 }; err.subdiagnostic(note); } else { - let note = errors::ItemWasCfgOut { span: cfg.span }; + let note = errors::ItemWasCfgOut { span: cfg.1 }; err.subdiagnostic(note); } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 99297de40d58..84d66c15f00c 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -3,11 +3,10 @@ use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; -use rustc_middle::{bug, ty}; +use rustc_middle::bug; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; -use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument}; @@ -20,11 +19,9 @@ use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, ToNameBinding, Used, Weak, errors, + ScopeSet, Segment, Used, Weak, errors, }; -type Visibility = ty::Visibility; - #[derive(Copy, Clone)] pub enum UsePrelude { No, @@ -464,13 +461,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = ( + let binding = this.arenas.new_pub_res_binding( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), - Visibility::Public, derive.span, LocalExpnId::ROOT, - ) - .to_name_binding(this.arenas); + ); result = Ok((binding, Flags::empty())); break; } @@ -1637,11 +1632,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(next_module) = binding.module() { - if self.mods_with_parse_errors.contains(&next_module.def_id()) { + if let Some(def_id) = binding.res().module_like_def_id() { + if self.mods_with_parse_errors.contains(&def_id) { module_had_parse_errors = true; } - module = Some(ModuleOrUniformRoot::Module(next_module)); + module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); record_segment_res(self, res); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 40c63a3edf3c..9a031ee03e0a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -11,7 +11,8 @@ use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_hir::def_id::DefId; use rustc_middle::metadata::{ModChild, Reexport}; -use rustc_middle::{span_bug, ty}; +use rustc_middle::span_bug; +use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, @@ -88,7 +89,7 @@ pub(crate) enum ImportKind<'ra> { is_prelude: bool, // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. - max_vis: Cell>, + max_vis: Cell>, id: NodeId, }, ExternCrate { @@ -185,7 +186,7 @@ pub(crate) struct ImportData<'ra> { /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition | /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell>>, - pub vis: ty::Visibility, + pub vis: Visibility, } /// All imports are unique and allocated on a same arena, @@ -679,9 +680,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { NameBindingKind::Res(res) => { Some(self.def_id_to_node_id(res.def_id().expect_local())) } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id(module.def_id().expect_local())) - } NameBindingKind::Import { import, .. } => import.id(), }; if let Some(binding_id) = binding_id { @@ -875,7 +873,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - this.define(parent, target, ns, imported_binding); + this.define_binding(parent, target, ns, imported_binding); PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { @@ -1283,7 +1281,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !binding.vis.is_at_least(import.vis, this.tcx) { reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis + if let Visibility::Restricted(binding_def_id) = binding.vis && binding_def_id.is_top_level_module() { crate_private_reexport = true; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 44a567f78100..3ef98100d094 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -28,7 +28,7 @@ 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::DelegationFnSig; +use rustc_middle::ty::{DelegationFnSig, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint::{self, BuiltinLintDiag}; @@ -638,8 +638,8 @@ impl PathSource<'_, '_, '_> { enum MaybeExported<'a> { Ok(NodeId), Impl(Option), - ImplItem(Result), - NestedUse(&'a Visibility), + ImplItem(Result), + NestedUse(&'a ast::Visibility), } impl MaybeExported<'_> { @@ -3463,7 +3463,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span, "error should be emitted when an unexpected trait item is used", ); - rustc_middle::ty::Visibility::Public + Visibility::Public }; this.r.feed_visibility(this.r.feed(id), vis); }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b669796bb021..a4601cb44ebf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2656,18 +2656,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if result.is_some() || !name_binding.vis.is_visible_locally() { return; } - if let Some(module) = name_binding.module() { + if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id(); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( - module, + r.expect_module(module_def_id), ImportSuggestion { did: Some(def_id), descr: "module", @@ -2682,6 +2681,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { // add the module to the lookup if seen_modules.insert(module_def_id) { + let module = r.expect_module(module_def_id); worklist.push((module, path_segments, doc_visible)); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f8d1b6783e39..b0b29bc2eae2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -36,12 +36,12 @@ use late::{ }; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, NodeId, Path, attr, }; +use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; @@ -65,7 +65,7 @@ use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{ self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt, - ResolverOutputs, TyCtxt, TyCtxtFeed, + ResolverOutputs, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; @@ -579,7 +579,7 @@ struct ModuleData<'ra> { globs: RefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell)]>>>, + traits: RefCell, Option>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -655,12 +655,12 @@ impl<'ra> Module<'ra> { let mut traits = self.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); - self.for_each_child(resolver, |_, name, ns, binding| { + self.for_each_child(resolver, |r, name, ns, binding| { if ns != TypeNS { return; } - if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { - collected_traits.push((name, binding)) + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { + collected_traits.push((name, binding, r.as_mut().get_module(def_id))) } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -674,7 +674,6 @@ impl<'ra> Module<'ra> { } } - // Public for rustdoc. fn def_id(self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } @@ -749,7 +748,7 @@ struct NameBindingData<'ra> { warn_ambiguity: bool, expansion: LocalExpnId, span: Span, - vis: ty::Visibility, + vis: Visibility, } /// All name bindings are unique and allocated on a same arena, @@ -769,20 +768,9 @@ impl std::hash::Hash for NameBindingData<'_> { } } -trait ToNameBinding<'ra> { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>; -} - -impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { - fn to_name_binding(self, _: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - self - } -} - #[derive(Clone, Copy, Debug)] enum NameBindingKind<'ra> { Res(Res), - Module(Module<'ra>), Import { binding: NameBinding<'ra>, import: Import<'ra> }, } @@ -875,18 +863,9 @@ struct AmbiguityError<'ra> { } impl<'ra> NameBindingData<'ra> { - fn module(&self) -> Option> { - match self.kind { - NameBindingKind::Module(module) => Some(module), - NameBindingKind::Import { binding, .. } => binding.module(), - _ => None, - } - } - fn res(&self) -> Res { match self.kind { NameBindingKind::Res(res) => res, - NameBindingKind::Module(module) => module.res().unwrap(), NameBindingKind::Import { binding, .. } => binding.res(), } } @@ -921,7 +900,7 @@ impl<'ra> NameBindingData<'ra> { DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, )) => true, - NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, + NameBindingKind::Res(..) => false, } } @@ -930,11 +909,7 @@ impl<'ra> NameBindingData<'ra> { NameBindingKind::Import { import, .. } => { matches!(import.kind, ImportKind::ExternCrate { .. }) } - NameBindingKind::Module(module) - if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind => - { - def_id.is_crate_root() - } + NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(), _ => false, } } @@ -1108,7 +1083,7 @@ pub struct Resolver<'ra, 'tcx> { /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, glob_error: Option, - visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, + visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, @@ -1181,7 +1156,7 @@ pub struct Resolver<'ra, 'tcx> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility - struct_constructors: LocalDefIdMap<(Res, ty::Visibility, Vec>)>, + struct_constructors: LocalDefIdMap<(Res, Visibility, Vec>)>, lint_buffer: LintBuffer, @@ -1255,6 +1230,32 @@ pub struct ResolverArenas<'ra> { } impl<'ra> ResolverArenas<'ra> { + fn new_res_binding( + &'ra self, + res: Res, + vis: Visibility, + span: Span, + expansion: LocalExpnId, + ) -> NameBinding<'ra> { + self.alloc_name_binding(NameBindingData { + kind: NameBindingKind::Res(res), + ambiguity: None, + warn_ambiguity: false, + vis, + span, + expansion, + }) + } + + fn new_pub_res_binding( + &'ra self, + res: Res, + span: Span, + expn_id: LocalExpnId, + ) -> NameBinding<'ra> { + self.new_res_binding(res, Visibility::Public, span, expn_id) + } + fn new_module( &'ra self, parent: Option>, @@ -1278,8 +1279,8 @@ impl<'ra> ResolverArenas<'ra> { } if let Some(def_id) = def_id { module_map.insert(def_id, module); - let vis = ty::Visibility::::Public; - let binding = (module, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); + let res = module.res().unwrap(); + let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT); module_self_bindings.insert(module, binding); } module @@ -1470,8 +1471,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let registered_tools = tcx.registered_tools(()); - - let pub_vis = ty::Visibility::::Public; let edition = tcx.sess.edition(); let mut resolver = Resolver { @@ -1520,12 +1519,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_expanded_macro_export_errors: BTreeSet::new(), arenas, - dummy_binding: (Res::Err, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas), + dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_types_bindings: PrimTy::ALL .iter() .map(|prim_ty| { - let binding = (Res::PrimTy(*prim_ty), pub_vis, DUMMY_SP, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::PrimTy(*prim_ty); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (prim_ty.name(), binding) }) .collect(), @@ -1533,16 +1532,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .iter() .map(|builtin_attr| { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name)); - let binding = - (res, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (builtin_attr.name, binding) }) .collect(), registered_tool_bindings: registered_tools .iter() .map(|ident| { - let binding = (Res::ToolMod, pub_vis, ident.span, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::ToolMod; + let binding = arenas.new_pub_res_binding(res, ident.span, LocalExpnId::ROOT); (*ident, binding) }) .collect(), @@ -1605,7 +1603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let root_parent_scope = ParentScope::module(graph_root, &resolver); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); - resolver.feed_visibility(crate_feed, ty::Visibility::Public); + resolver.feed_visibility(crate_feed, Visibility::Public); resolver } @@ -1659,7 +1657,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Default::default() } - fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: ty::Visibility) { + fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: Visibility) { let feed = feed.upgrade(self.tcx); feed.visibility(vis.to_def_id()); self.visibilities_for_hashing.push((feed.def_id(), vis)); @@ -1837,10 +1835,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { module.ensure_traits(self); let traits = module.traits.borrow(); - for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { - if self.trait_may_have_item(trait_binding.module(), assoc_item) { + for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { + if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); - let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); + let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name); found_traits.push(TraitCandidate { def_id, import_ids }); } } @@ -2110,11 +2108,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.pat_span_map.insert(node, span); } - fn is_accessible_from( - &self, - vis: ty::Visibility>, - module: Module<'ra>, - ) -> bool { + fn is_accessible_from(&self, vis: Visibility>, module: Module<'ra>) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } @@ -2174,9 +2168,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? }; - let crate_root = self.expect_module(crate_id.as_def_id()); - let vis = ty::Visibility::::Public; - (crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) }) }); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5864b035f73d..c17d74659db3 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,10 +5,9 @@ use std::cell::Cell; use std::mem; use std::sync::Arc; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::StabilityLevel; +use rustc_attr_data_structures::{CfgEntry, StabilityLevel, StrippedCfgItem}; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, @@ -21,7 +20,7 @@ use rustc_expand::expand::{ use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; -use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility}; +use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, @@ -42,7 +41,7 @@ use crate::imports::Import; use crate::{ BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, ToNameBinding, Used, + Resolver, ScopeSet, Segment, Used, }; type Res = def::Res; @@ -437,8 +436,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { .iter() .map(|(_, ident)| { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - let binding = (res, Visibility::::Public, ident.span, expn_id) - .to_name_binding(self.arenas); + let binding = self.arenas.new_pub_res_binding(res, ident.span, expn_id); (*ident, binding) }) .collect(); @@ -485,8 +483,18 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.proc_macros.push(self.local_def_id(id)) } - fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem) { - self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, ident, cfg }); + fn append_stripped_cfg_item( + &mut self, + parent_node: NodeId, + ident: Ident, + cfg: CfgEntry, + cfg_span: Span, + ) { + self.stripped_cfg_items.push(StrippedCfgItem { + parent_module: parent_node, + ident, + cfg: (cfg, cfg_span), + }); } fn registered_tools(&self) -> &RegisteredTools { diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs index 737550eb73e9..9912fad1756e 100644 --- a/compiler/rustc_type_ir/src/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -12,12 +12,6 @@ use crate::{self as ty, Interner}; // avoid heap allocations. type TypeWalkerStack = SmallVec<[::GenericArg; 8]>; -pub struct TypeWalker { - stack: TypeWalkerStack, - last_subtree: usize, - pub visited: SsoHashSet, -} - /// An iterator for walking the type tree. /// /// It's very easy to produce a deeply @@ -26,6 +20,12 @@ pub struct TypeWalker { /// in this situation walker only visits each type once. /// It maintains a set of visited types and /// skips any types that are already there. +pub struct TypeWalker { + stack: TypeWalkerStack, + last_subtree: usize, + pub visited: SsoHashSet, +} + impl TypeWalker { pub fn new(root: I::GenericArg) -> Self { Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4ad65e678c3d..6b6e4df4cba7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -155,6 +155,7 @@ #![feature(try_trait_v2)] #![feature(try_with_capacity)] #![feature(tuple_trait)] +#![feature(ub_checks)] #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1df6ab672eaa..9856e9c18ec6 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -64,7 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use core::{fmt, intrinsics}; +use core::{fmt, intrinsics, ub_checks}; #[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; @@ -1058,6 +1058,11 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_raw_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } @@ -1174,6 +1179,11 @@ impl Vec { #[unstable(feature = "allocator_api", reason = "new API", issue = "32838")] // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub unsafe fn from_parts_in(ptr: NonNull, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } } @@ -1950,7 +1960,11 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn set_len(&mut self, new_len: usize) { - debug_assert!(new_len <= self.capacity()); + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::set_len requires that new_len <= capacity()", + (new_len: usize = new_len, capacity: usize = self.capacity()) => new_len <= capacity + ); self.len = new_len; } @@ -3695,7 +3709,7 @@ impl Vec { /// This is optimal if: /// /// * The tail (elements in the vector after `range`) is empty, - /// * or `replace_with` yields fewer or equal elements than `range`’s length + /// * or `replace_with` yields fewer or equal elements than `range`'s length /// * or the lower bound of its `size_hint()` is exact. /// /// Otherwise, a temporary vector is allocated and the tail is moved twice. diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 16356f749c92..62203e132b70 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -374,9 +374,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] { } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl Index for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const Index for [T; N] where - [T]: Index, + [T]: ~const Index, { type Output = <[T] as Index>::Output; @@ -387,9 +388,10 @@ where } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl IndexMut for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const IndexMut for [T; N] where - [T]: IndexMut, + [T]: ~const IndexMut, { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6b9cbb064358..1b6dbc2f428f 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -196,16 +196,14 @@ pub macro assert_matches { }, } -/// A macro for defining `#[cfg]` match-like statements. +/// Selects code at compile-time based on `cfg` predicates. /// -/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of -/// `#[cfg]` cases, emitting the implementation which matches first. +/// This macro evaluates, at compile-time, a series of `cfg` predicates, +/// selects the first that is true, and emits the code guarded by that +/// predicate. The code guarded by other predicates is not emitted. /// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code -/// without having to rewrite each clause multiple times. -/// -/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when -/// all previous declarations do not evaluate to true. +/// An optional trailing `_` wildcard can be used to specify a fallback. If +/// none of the predicates are true, a [`compile_error`] is emitted. /// /// # Example /// @@ -225,7 +223,7 @@ pub macro assert_matches { /// } /// ``` /// -/// If desired, it is possible to return expressions through the use of surrounding braces: +/// The `cfg_select!` macro can also be used in expression position: /// /// ``` /// #![feature(cfg_select)] diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 55fa91d0b9f4..c460f38bd2e4 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -94,9 +94,9 @@ macro_rules! sh_impl_signed { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shr((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(-other as u32)) } else { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } } @@ -119,9 +119,9 @@ macro_rules! sh_impl_signed { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shl((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(-other as u32)) } else { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } } @@ -147,7 +147,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, @@ -168,7 +168,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, @@ -1052,39 +1052,3 @@ macro_rules! wrapping_int_impl_unsigned { } wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 } - -mod shift_max { - #![allow(non_upper_case_globals)] - - #[cfg(target_pointer_width = "16")] - mod platform { - pub(crate) const usize: u32 = super::u16; - pub(crate) const isize: u32 = super::i16; - } - - #[cfg(target_pointer_width = "32")] - mod platform { - pub(crate) const usize: u32 = super::u32; - pub(crate) const isize: u32 = super::i32; - } - - #[cfg(target_pointer_width = "64")] - mod platform { - pub(crate) const usize: u32 = super::u64; - pub(crate) const isize: u32 = super::i64; - } - - pub(super) const i8: u32 = (1 << 3) - 1; - pub(super) const i16: u32 = (1 << 4) - 1; - pub(super) const i32: u32 = (1 << 5) - 1; - pub(super) const i64: u32 = (1 << 6) - 1; - pub(super) const i128: u32 = (1 << 7) - 1; - pub(super) use self::platform::isize; - - pub(super) const u8: u32 = i8; - pub(super) const u16: u32 = i16; - pub(super) const u32: u32 = i32; - pub(super) const u64: u32 = i64; - pub(super) const u128: u32 = i128; - pub(super) use self::platform::usize; -} diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 8092fa9eb2fc..d8489e9a9491 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -55,6 +55,8 @@ #[doc(alias = "]")] #[doc(alias = "[")] #[doc(alias = "[]")] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -165,7 +167,9 @@ see chapter in The Book : Index { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[const_trait] +pub trait IndexMut: ~const Index { /// Performs the mutable indexing (`container[index]`) operation. /// /// # Panics diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 27b0c6830db6..2ad520b7ead7 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1524,10 +1524,11 @@ impl *const [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + pub const unsafe fn get_unchecked(self, index: I) -> *const I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked(self) } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 73efdf044541..579e2461103d 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1881,10 +1881,11 @@ impl *mut [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + pub const unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked_mut(self) } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index c4ca29a36797..62da6567cca7 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1597,10 +1597,11 @@ impl NonNull<[T]> { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + pub const unsafe fn get_unchecked_mut(self, index: I) -> NonNull where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. // As a consequence, the resulting pointer cannot be null. diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 2276112a27bb..5cd7956291ca 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -186,14 +186,17 @@ impl IntoBounds for Range { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::Range { #[inline] fn from(value: Range) -> Self { Self { start: value.start, end: value.end } } } + #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for Range { #[inline] fn from(value: legacy::Range) -> Self { Self { start: value.start, end: value.end } @@ -362,7 +365,8 @@ impl IntoBounds for RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeInclusive { #[inline] fn from(value: RangeInclusive) -> Self { Self::new(value.start, value.end) @@ -506,14 +510,16 @@ impl IntoBounds for RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeFrom { #[inline] fn from(value: RangeFrom) -> Self { Self { start: value.start } } } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for RangeFrom { #[inline] fn from(value: legacy::RangeFrom) -> Self { Self { start: value.start } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index f725c3fdd94c..322b3580eded 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { type Output = I::Output; @@ -19,9 +20,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { #[inline(always)] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -158,6 +160,8 @@ mod private_slice_index { message = "the type `{T}` cannot be indexed by `{Self}`", label = "slice indices are of type `usize` or ranges of `usize`" )] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -208,7 +212,8 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The methods `index` and `index_mut` panic if the index is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -278,7 +283,8 @@ unsafe impl SliceIndex<[T]> for usize { /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here /// than there are for a general `Range` (which might be `100..3`). -unsafe impl SliceIndex<[T]> for ops::IndexRange { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::IndexRange { type Output = [T]; #[inline] @@ -354,7 +360,8 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -453,7 +460,8 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::Range { type Output = [T]; #[inline] @@ -491,7 +499,8 @@ unsafe impl SliceIndex<[T]> for range::Range { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -529,7 +538,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeTo { /// The methods `index` and `index_mut` panic if the start of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -574,7 +584,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeFrom { type Output = [T]; #[inline] @@ -611,7 +622,8 @@ unsafe impl SliceIndex<[T]> for range::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -650,7 +662,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFull { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -693,7 +706,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeInclusive { type Output = [T]; #[inline] @@ -731,7 +745,8 @@ unsafe impl SliceIndex<[T]> for range::RangeInclusive { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index abcba5a621e2..32419024db95 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -568,9 +568,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get(&self, index: I) -> Option<&I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get(self) } @@ -594,9 +595,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get_mut(self) } @@ -633,9 +635,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked(&self, index: I) -> &I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; // the slice is dereferenceable because `self` is a safe reference. @@ -677,9 +680,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; // the slice is dereferenceable because `self` is a safe reference. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index fba3436496e3..18a516c0f608 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -589,8 +589,9 @@ impl str { /// assert!(v.get(..42).is_none()); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get>(&self, i: I) -> Option<&I::Output> { + pub const fn get>(&self, i: I) -> Option<&I::Output> { i.get(self) } @@ -621,8 +622,9 @@ impl str { /// assert_eq!("HEllo", v); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + pub const fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { i.get_mut(self) } @@ -952,6 +954,7 @@ impl str { /// /// The caller must ensure that `mid` is a valid byte offset from the start /// of the string and falls on the boundary of a UTF-8 code point. + #[inline] const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) { let len = self.len(); let ptr = self.as_ptr(); diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index b9559c831713..42ffc591b5bb 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -49,9 +49,10 @@ impl PartialOrd for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for str where - I: SliceIndex, + I: ~const SliceIndex, { type Output = I::Output; @@ -62,9 +63,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for str where - I: SliceIndex, + I: ~const SliceIndex, { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -92,7 +94,8 @@ const fn str_index_overflow_fail() -> ! { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFull { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -156,7 +159,8 @@ unsafe impl SliceIndex for ops::RangeFull { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -260,7 +264,8 @@ unsafe impl SliceIndex for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -431,7 +436,8 @@ unsafe impl SliceIndex for (ops::Bound, ops::Bound) { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeTo { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -499,7 +505,8 @@ unsafe impl SliceIndex for ops::RangeTo { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -554,7 +561,8 @@ unsafe impl SliceIndex for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -625,7 +633,8 @@ unsafe impl SliceIndex for range::RangeFrom { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -662,7 +671,8 @@ unsafe impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -713,7 +723,8 @@ unsafe impl SliceIndex for range::RangeInclusive { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 38df09a91c10..36d6a20a9442 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,9 +1,7 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -use core::ops::{Add, Div, Mul, Sub}; use std::f128::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -38,160 +36,9 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; /// Second pattern over the mantissa const NAN_MASK2: u128 = 0x00005555555555555555555555555555; -#[test] -fn test_num_f128() { - // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` - // function is available on all platforms. - let ten = 10f128; - let two = 2f128; - assert_biteq!(ten.add(two), ten + two); - assert_biteq!(ten.sub(two), ten - two); - assert_biteq!(ten.mul(two), ten * two); - assert_biteq!(ten.div(two), ten / two); - #[cfg(any(miri, target_has_reliable_f128_math))] - assert_biteq!(core::ops::Rem::rem(ten, two), ten % two); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f128 = f128::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f128 = 0.0f128; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f128 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f128 = 1.0f128; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f128.is_nan()); - assert!(!5.3f128.is_nan()); - assert!(!(-10.732f128).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f128.is_infinite()); - assert!(!42.8f128.is_infinite()); - assert!(!(-109.2f128).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f128.is_finite()); - assert!(42.8f128.is_finite()); - assert!((-109.2f128).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f128.is_normal()); - assert!(1e-4931f128.is_normal()); - assert!(!1e-4932f128.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f128.classify(), Fp::Normal); - assert_eq!(1e-4931f128.classify(), Fp::Normal); - assert_eq!(1e-4932f128.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index f6749d796cca..351c008a37ba 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f16)] use std::f16::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -43,151 +42,9 @@ const NAN_MASK1: u16 = 0x02aa; /// Second pattern over the mantissa const NAN_MASK2: u16 = 0x0155; -#[test] -fn test_num_f16() { - super::test_num(10f16, 2f16); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f16 = f16::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f16 = 0.0f16; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f16 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f16 = 1.0f16; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f16.is_nan()); - assert!(!5.3f16.is_nan()); - assert!(!(-10.732f16).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f16.is_infinite()); - assert!(!42.8f16.is_infinite()); - assert!(!(-109.2f16).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f16.is_finite()); - assert!(42.8f16.is_finite()); - assert!((-109.2f16).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f16.is_normal()); - assert!(1e-4f16.is_normal()); - assert!(!1e-5f16.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f16.classify(), Fp::Normal); - assert_eq!(1e-4f16.classify(), Fp::Normal); - assert_eq!(1e-5f16.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index f5d5723fea45..267b0e4e2943 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,6 +1,5 @@ use core::f32; use core::f32::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -30,148 +29,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_num_f32() { - super::test_num(10f32, 2f32); -} - -#[test] -fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f32 = 0.0f32; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f32 = 1.0f32; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 34af87c241e9..735b7a765151 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,6 +1,5 @@ use core::f64; use core::f64::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -25,147 +24,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_num_f64() { - super::test_num(10f64, 2f64); -} - -#[test] -fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f64 = 0.0f64; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f64 = 1.0f64; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 36743a7d6df9..43431bba6954 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,28 +1,40 @@ -use std::fmt; use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Set the default tolerance for float comparison based on the type. -trait Approx { - const LIM: Self; +trait TestableFloat { + /// Set the default tolerance for float comparison based on the type. + const APPROX: Self; + const MIN_POSITIVE_NORMAL: Self; + const MAX_SUBNORMAL: Self; } -impl Approx for f16 { - const LIM: Self = 1e-3; +impl TestableFloat for f16 { + const APPROX: Self = 1e-3; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f32 { - const LIM: Self = 1e-6; + +impl TestableFloat for f32 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f64 { - const LIM: Self = 1e-6; + +impl TestableFloat for f64 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f128 { - const LIM: Self = 1e-9; + +impl TestableFloat for f128 { + const APPROX: Self = 1e-9; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } /// Determine the tolerance for values of the argument type. -const fn lim_for_ty(_x: T) -> T { - T::LIM +const fn lim_for_ty(_x: T) -> T { + T::APPROX } // We have runtime ("rt") and const versions of these macros. @@ -187,9 +199,11 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { #[allow(unused)] - use super::Approx; + use super::TestableFloat; #[allow(unused)] use std::num::FpCategory as Fp; + #[allow(unused)] + use std::ops::{Add, Div, Mul, Rem, Sub}; // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] use $crate::floats::{ @@ -229,30 +243,42 @@ macro_rules! float_test { }; } -/// Helper function for testing numeric operations -pub fn test_num(ten: T, two: T) -where - T: PartialEq - + Add - + Sub - + Mul - + Div - + Rem - + fmt::Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} - mod f128; mod f16; mod f32; mod f64; +float_test! { + name: num, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.add(two), ten + two); + assert_biteq!(ten.sub(two), ten - two); + assert_biteq!(ten.mul(two), ten * two); + assert_biteq!(ten.div(two), ten / two); + } +} + +// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on +// all platforms. +float_test! { + name: num_rem, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.rem(two), ten % two); + } +} + float_test! { name: nan, attrs: { @@ -273,6 +299,213 @@ float_test! { } } +float_test! { + name: infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let inf: Float = Float::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert!(matches!(inf.classify(), Fp::Infinite)); + } +} + +float_test! { + name: neg_infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_inf: Float = Float::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + } +} + +float_test! { + name: zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let zero: Float = 0.0; + assert_biteq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert!(matches!(zero.classify(), Fp::Zero)); + } +} + +float_test! { + name: neg_zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_zero: Float = -0.0; + assert!(0.0 == neg_zero); + assert_biteq!(-0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + } +} + +float_test! { + name: one, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let one: Float = 1.0; + assert_biteq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert!(matches!(one.classify(), Fp::Normal)); + } +} + +float_test! { + name: is_nan, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 5.3; + let neg: Float = -10.732; + assert!(nan.is_nan()); + assert!(!zero.is_nan()); + assert!(!pos.is_nan()); + assert!(!neg.is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); + } +} + +float_test! { + name: is_infinite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!zero.is_infinite()); + assert!(!pos.is_infinite()); + assert!(!neg.is_infinite()); + } +} + +float_test! { + name: is_finite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(zero.is_finite()); + assert!(pos.is_finite()); + assert!(neg.is_finite()); + } +} + +float_test! { + name: is_normal, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one : Float = 1.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(one.is_normal()); + assert!(Float::MIN_POSITIVE_NORMAL.is_normal()); + assert!(!Float::MAX_SUBNORMAL.is_normal()); + } +} + +float_test! { + name: classify, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one: Float = 1.0; + assert!(matches!(nan.classify(), Fp::Nan)); + assert!(matches!(inf.classify(), Fp::Infinite)); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + assert!(matches!(zero.classify(), Fp::Zero)); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + assert!(matches!(one.classify(), Fp::Normal)); + assert!(matches!(Float::MIN_POSITIVE_NORMAL.classify(), Fp::Normal)); + assert!(matches!(Float::MAX_SUBNORMAL.classify(), Fp::Subnormal)); + } +} + float_test! { name: min, attrs: { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index fdef736c0c0f..e2249bd7f6a1 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_float_round_methods)] +#![feature(const_ops)] #![feature(const_ref_cell)] #![feature(const_trait_impl)] #![feature(core_float_math)] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 62ece4b69619..86d23df52381 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -92,6 +92,9 @@ backtrace = [ 'object/rustc-dep-of-std', 'miniz_oxide/rustc-dep-of-std', ] +# Disable symbolization in backtraces. For use with -Zbuild-std. +# FIXME: Ideally this should be an additive backtrace-symbolization feature +backtrace-trace-only = [] panic-unwind = ["dep:panic_unwind"] compiler-builtins-c = ["alloc/compiler-builtins-c"] diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index efa6a896dad8..272d0fa4d1a1 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -68,61 +68,67 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: return false; } - let mut hit = false; - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; + if cfg!(feature = "backtrace-trace-only") { + const HEX_WIDTH: usize = 2 + 2 * size_of::(); + let frame_ip = frame.ip(); + res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); + } else { + let mut hit = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; - // `__rust_end_short_backtrace` means we are done hiding symbols - // for now. Print until we see `__rust_begin_short_backtrace`. - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_end_short_backtrace") { - print = true; - return; - } - if print && sym.contains("__rust_begin_short_backtrace") { - print = false; - return; - } - if !print { - omitted_count += 1; + // `__rust_end_short_backtrace` means we are done hiding symbols + // for now. Print until we see `__rust_begin_short_backtrace`. + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_end_short_backtrace") { + print = true; + return; + } + if print && sym.contains("__rust_begin_short_backtrace") { + print = false; + return; + } + if !print { + omitted_count += 1; + } } } - } - if print { - if omitted_count > 0 { - debug_assert!(print_fmt == PrintFmt::Short); - // only print the message between the middle of frames - if !first_omit { - let _ = writeln!( - bt_fmt.formatter(), - " [... omitted {} frame{} ...]", - omitted_count, - if omitted_count > 1 { "s" } else { "" } - ); + if print { + if omitted_count > 0 { + debug_assert!(print_fmt == PrintFmt::Short); + // only print the message between the middle of frames + if !first_omit { + let _ = writeln!( + bt_fmt.formatter(), + " [... omitted {} frame{} ...]", + omitted_count, + if omitted_count > 1 { "s" } else { "" } + ); + } + first_omit = false; + omitted_count = 0; } - first_omit = false; - omitted_count = 0; + res = bt_fmt.frame().symbol(frame, symbol); } - res = bt_fmt.frame().symbol(frame, symbol); + }); + #[cfg(target_os = "nto")] + if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { + if !hit && print { + use crate::backtrace_rs::SymbolName; + res = bt_fmt.frame().print_raw( + frame.ip(), + Some(SymbolName::new("__my_thread_exit".as_bytes())), + None, + None, + ); + } + return false; } - }); - #[cfg(target_os = "nto")] - if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && print { - use crate::backtrace_rs::SymbolName; - res = bt_fmt.frame().print_raw( - frame.ip(), - Some(SymbolName::new("__my_thread_exit".as_bytes())), - None, - None, - ); + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } - return false; - } - if !hit && print { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } idx += 1; diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 7cd448733130..0ad014ccd3e2 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -469,6 +469,29 @@ impl LocalKey> { pub fn replace(&'static self, value: T) -> T { self.with(|cell| cell.replace(value)) } + + /// Updates the contained value using a function. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_update)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell = const { Cell::new(5) }; + /// } + /// + /// X.update(|x| x + 1); + /// assert_eq!(X.get(), 6); + /// ``` + #[unstable(feature = "local_key_cell_update", issue = "143989")] + pub fn update(&'static self, f: impl FnOnce(T) -> T) + where + T: Copy, + { + self.with(|cell| cell.update(f)) + } } impl LocalKey> { diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 290c2eeed44c..032f5272a9cd 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -20,6 +20,7 @@ test = { path = "../test", public = true } [features] default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] backtrace = ["std/backtrace"] +backtrace-trace-only = ["std/backtrace-trace-only"] compiler-builtins-c = ["std/compiler-builtins-c"] compiler-builtins-mem = ["std/compiler-builtins-mem"] compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index fcb6abea4347..c2ad9a4df597 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -11,7 +11,6 @@ pub(crate) mod llvm; pub(crate) mod perf; pub(crate) mod run; pub(crate) mod setup; -pub(crate) mod suggest; pub(crate) mod synthetic_targets; pub(crate) mod test; pub(crate) mod tool; diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs deleted file mode 100644 index fd4918961adb..000000000000 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Attempt to magically identify good tests to run - -use std::path::PathBuf; -use std::str::FromStr; - -use clap::Parser; - -use crate::core::build_steps::tool::Tool; -use crate::core::builder::Builder; - -/// Suggests a list of possible `x.py` commands to run based on modified files in branch. -pub fn suggest(builder: &Builder<'_>, run: bool) { - let git_config = builder.config.git_config(); - let suggestions = builder - .tool_cmd(Tool::SuggestTests) - .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) - .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email) - .run_capture_stdout(builder) - .stdout(); - - let suggestions = suggestions - .lines() - .map(|line| { - let mut sections = line.split_ascii_whitespace(); - - // this code expects one suggestion per line in the following format: - // {some number of flags} [optional stage number] - let cmd = sections.next().unwrap(); - let stage = sections.next_back().and_then(|s| str::parse(s).ok()); - let paths: Vec = sections.map(|p| PathBuf::from_str(p).unwrap()).collect(); - - (cmd, stage, paths) - }) - .collect::>(); - - if !suggestions.is_empty() { - println!("==== SUGGESTIONS ===="); - for sug in &suggestions { - print!("x {} ", sug.0); - if let Some(stage) = sug.1 { - print!("--stage {stage} "); - } - - for path in &sug.2 { - print!("{} ", path.display()); - } - println!(); - } - println!("====================="); - } else { - println!("No suggestions found!"); - return; - } - - if run { - for sug in suggestions { - let mut build: crate::Build = builder.build.clone(); - build.config.paths = sug.2; - build.config.cmd = crate::core::config::flags::Flags::parse_from(["x.py", sug.0]).cmd; - if let Some(stage) = sug.1 { - build.config.stage = stage; - } - build.build(); - } - } else { - println!("HELP: consider using the `--run` flag to automatically run suggested tests"); - } -} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 757eac1475c1..9e7ea5c115f1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -47,12 +47,11 @@ impl Step for CrateBootstrap { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - // This step is responsible for several different tool paths. By default - // it will test all of them, but requesting specific tools on the - // command-line (e.g. `./x test suggest-tests`) will test only the - // specified tools. + // This step is responsible for several different tool paths. + // + // By default, it will test all of them, but requesting specific tools on the command-line + // (e.g. `./x test src/tools/coverage-dump`) will test only the specified tools. run.path("src/tools/jsondoclint") - .path("src/tools/suggest-tests") .path("src/tools/replace-version-placeholder") .path("src/tools/coverage-dump") // We want `./x test tidy` to _run_ the tidy tool, not its tests. diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 814a44b9a13b..1c994b0ccfc8 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -517,7 +517,6 @@ bootstrap_tool!( ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; - SuggestTests, "src/tools/suggest-tests", "suggest-tests"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index d5a290d804c5..a3b471ca56eb 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -113,7 +113,7 @@ impl Cargo { match cmd_kind { // No need to configure the target linker for these command types. - Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {} + Kind::Clean | Kind::Check | Kind::Format | Kind::Setup => {} _ => { cargo.configure_linker(builder, mode); } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 7115c5a1cbe7..1b75d00b30e4 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -845,7 +845,6 @@ pub enum Kind { #[value(alias = "r")] Run, Setup, - Suggest, Vendor, Perf, } @@ -869,7 +868,6 @@ impl Kind { Kind::Install => "install", Kind::Run => "run", Kind::Setup => "setup", - Kind::Suggest => "suggest", Kind::Vendor => "vendor", Kind::Perf => "perf", } @@ -881,7 +879,6 @@ impl Kind { Kind::Bench => "Benchmarking", Kind::Doc => "Documenting", Kind::Run => "Running", - Kind::Suggest => "Suggesting", Kind::Clippy => "Linting", Kind::Perf => "Profiling & benchmarking", _ => { @@ -1201,7 +1198,7 @@ impl<'a> Builder<'a> { Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() - Kind::Format | Kind::Suggest | Kind::Perf => vec![], + Kind::Format | Kind::Perf => vec![], Kind::MiriTest | Kind::MiriSetup => unreachable!(), } } @@ -1269,7 +1266,6 @@ impl<'a> Builder<'a> { Subcommand::Run { .. } => (Kind::Run, &paths[..]), Subcommand::Clean { .. } => (Kind::Clean, &paths[..]), Subcommand::Format { .. } => (Kind::Format, &[][..]), - Subcommand::Suggest { .. } => (Kind::Suggest, &[][..]), Subcommand::Setup { profile: ref path } => ( Kind::Setup, path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)), diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0039d44785c3..28958b60fc32 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1050,7 +1050,6 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } | Subcommand::Vendor { .. } => flags_stage.unwrap_or(0), }; @@ -1098,7 +1097,6 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } | Subcommand::Vendor { .. } | Subcommand::Perf { .. } => {} } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 155b6f587589..1547ca444943 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -481,13 +481,6 @@ Arguments: #[arg(value_name = "|hook|editor|link")] profile: Option, }, - /// Suggest a subset of tests to run, based on modified files - #[command(long_about = "\n")] - Suggest { - /// run suggested tests - #[arg(long)] - run: bool, - }, /// Vendor dependencies Vendor { /// Additional `Cargo.toml` to sync and vendor @@ -518,7 +511,6 @@ impl Subcommand { Subcommand::Install => Kind::Install, Subcommand::Run { .. } => Kind::Run, Subcommand::Setup { .. } => Kind::Setup, - Subcommand::Suggest { .. } => Kind::Suggest, Subcommand::Vendor { .. } => Kind::Vendor, Subcommand::Perf { .. } => Kind::Perf, } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index f2119e84cce7..b39d464493e5 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -216,7 +216,6 @@ than building it. build.config.cmd, Subcommand::Clean { .. } | Subcommand::Check { .. } - | Subcommand::Suggest { .. } | Subcommand::Format { .. } | Subcommand::Setup { .. } ); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 66a164703b7f..44be51815c7c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -651,11 +651,9 @@ impl Build { // Handle hard-coded subcommands. { #[cfg(feature = "tracing")] - let _hardcoded_span = span!( - tracing::Level::DEBUG, - "handling hardcoded subcommands (Format, Suggest, Perf)" - ) - .entered(); + let _hardcoded_span = + span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Perf)") + .entered(); match &self.config.cmd { Subcommand::Format { check, all } => { @@ -666,9 +664,6 @@ impl Build { &self.config.paths, ); } - Subcommand::Suggest { run } => { - return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run); - } Subcommand::Perf(args) => { return core::build_steps::perf::perf(&builder::Builder::new(self), args); } diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index dcafeb80f90c..d3926df9650c 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -67,7 +67,6 @@ pub fn fill_compilers(build: &mut Build) { // We don't need to check cross targets for these commands. crate::Subcommand::Clean { .. } | crate::Subcommand::Check { .. } - | crate::Subcommand::Suggest { .. } | crate::Subcommand::Format { .. } | crate::Subcommand::Setup { .. } => { build.hosts.iter().cloned().chain(iter::once(build.host_target)).collect() @@ -221,10 +220,15 @@ fn default_compiler( } t if t.contains("-wasi") => { - let root = build - .wasi_sdk_path - .as_ref() - .expect("WASI_SDK_PATH mut be configured for a -wasi target"); + let root = if let Some(path) = build.wasi_sdk_path.as_ref() { + path + } else { + if build.config.is_running_on_ci { + panic!("ERROR: WASI_SDK_PATH must be configured for a -wasi target on CI"); + } + println!("WARNING: WASI_SDK_PATH not set, using default cc/cxx compiler"); + return None; + }; let compiler = match compiler { Language::C => format!("{t}-clang"), Language::CPlusPlus => format!("{t}-clang++"), diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1f6ed8129da8..d888a7863bcb 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -476,4 +476,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Option `tool.TOOL_NAME.features` now works on any subcommand, not just `build`.", }, + ChangeInfo { + change_id: 143630, + severity: ChangeSeverity::Warning, + summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.", + }, ]; diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index 862c44496241..9b1ccc32cb61 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -43,7 +43,7 @@ pub(crate) struct BuildMetrics { state: RefCell, } -/// NOTE: this isn't really cloning anything, but `x suggest` doesn't need metrics so this is probably ok. +// NOTE: this isn't really cloning anything, but necessary for `Build: Clone`. impl Clone for BuildMetrics { fn clone(&self) -> Self { Self::init() diff --git a/src/doc/book b/src/doc/book index ef1ce8f87a8b..b2d1a0821e12 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ef1ce8f87a8b18feb1b6a9cf9a4939a79bde6795 +Subproject commit b2d1a0821e12a676b496d61891b8e3d374a8e832 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 41f688a598a5..fe88fbb68391 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 41f688a598a5022b749e23d37f3c524f6a0b28e1 +Subproject commit fe88fbb68391a465680dd91109f0a151a1676f3e diff --git a/src/doc/nomicon b/src/doc/nomicon index 8b61acfaea82..3ff384320598 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8b61acfaea822e9ac926190bc8f15791c33336e8 +Subproject commit 3ff384320598bbe8d8cfe5cb8f18f78a3a3e6b15 diff --git a/src/doc/reference b/src/doc/reference index e9fc99f10784..1f45bd41fa6c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit e9fc99f107840813916f62e16b3f6d9556e1f2d8 +Subproject commit 1f45bd41fa6c17b7c048ed6bfe5f168c4311206a diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 288b4e4948ad..e386be5f44af 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 288b4e4948add43f387cad35adc7b1c54ca6fe12 +Subproject commit e386be5f44af711854207c11fdd61bb576270b04 diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 7f2f32c62ffb..651e2925ad50 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -35,7 +35,6 @@ - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md) - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md) - [Performance testing](./tests/perf.md) - - [Suggest tests tool](./tests/suggest-tests.md) - [Misc info](./tests/misc.md) - [Debugging the compiler](./compiler-debugging.md) - [Using the tracing/logging instrumentation](./tracing.md) diff --git a/src/doc/rustc-dev-guide/src/building/quickstart.md b/src/doc/rustc-dev-guide/src/building/quickstart.md index 9a8ab353e029..97314d803695 100644 --- a/src/doc/rustc-dev-guide/src/building/quickstart.md +++ b/src/doc/rustc-dev-guide/src/building/quickstart.md @@ -61,9 +61,6 @@ and check the output. Use `--bless` if you've made a change and want to update the `.stderr` files with the new output. -> `./x suggest` can also be helpful for suggesting which tests to run after a -> change. - Congrats, you are now ready to make a change to the compiler! If you have more questions, [the full chapter](./how-to-build-and-run.md) might contain the answers, and if it doesn't, feel free to ask for help on diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index bfb2f4d1084a..7f626314f718 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -270,23 +270,6 @@ run the tests at some later time. You can then use `git bisect` to track down is that you are left with a fairly fine-grained set of commits at the end, all of which build and pass tests. This often helps reviewing. -## `x suggest` - -The `x suggest` subcommand suggests (and runs) a subset of the extensive -`rust-lang/rust` tests based on files you have changed. This is especially -useful for new contributors who have not mastered the arcane `x` flags yet and -more experienced contributors as a shorthand for reducing mental effort. In all -cases it is useful not to run the full tests (which can take on the order of -tens of minutes) and just run a subset which are relevant to your changes. For -example, running `tidy` and `linkchecker` is useful when editing Markdown files, -whereas UI tests are much less likely to be helpful. While `x suggest` is a -useful tool, it does not guarantee perfect coverage (just as PR CI isn't a -substitute for bors). See the [dedicated chapter](../tests/suggest-tests.md) for -more information and contribution instructions. - -Please note that `x suggest` is in a beta state currently and the tests that it -will suggest are limited. - ## Configuring `rustup` to use nightly Some parts of the bootstrap process uses pinned, nightly versions of tools like diff --git a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md b/src/doc/rustc-dev-guide/src/tests/suggest-tests.md deleted file mode 100644 index 663e8a5af3b9..000000000000 --- a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md +++ /dev/null @@ -1,59 +0,0 @@ -# Suggest tests tool - -This chapter is about the internals of and contribution instructions for the -`suggest-tests` tool. For a high-level overview of the tool, see [this -section](../building/suggested.md#x-suggest). This tool is currently in a beta -state and is tracked by [this](https://github.com/rust-lang/rust/issues/109933) -issue on Github. Currently the number of tests it will suggest are very limited -in scope, we are looking to expand this (contributions welcome!). - -## Internals - -The tool is defined in a separate crate -([`src/tools/suggest-tests`](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests)) -which outputs suggestions which are parsed by a shim in bootstrap -([`src/bootstrap/src/core/build_steps/suggest.rs`](https://github.com/rust-lang/rust/blob/master/src/bootstrap/src/core/build_steps/suggest.rs)). -The only notable thing the bootstrap shim does is (when invoked with the `--run` -flag) use bootstrap's internal mechanisms to create a new `Builder` and uses it -to invoke the suggested commands. The `suggest-tests` crate is where the fun -happens, two kinds of suggestions are defined: "static" and "dynamic" -suggestions. - -### Static suggestions - -Defined -[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/static_suggestions.rs). -Static suggestions are simple: they are just -[globs](https://crates.io/crates/glob) which map to a `x` command. In -`suggest-tests`, this is implemented with a simple `macro_rules` macro. - -### Dynamic suggestions - -Defined -[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/dynamic_suggestions.rs). -These are more complicated than static suggestions and are implemented as -functions with the following signature: `fn(&Path) -> Vec`. In other -words, each suggestion takes a path to a modified file and (after running -arbitrary Rust code) can return any number of suggestions, or none. Dynamic -suggestions are useful for situations where fine-grained control over -suggestions is needed. For example, modifications to the `compiler/xyz/` path -should trigger the `x test compiler/xyz` suggestion. In the future, dynamic -suggestions might even read file contents to determine if (what) tests should -run. - -## Adding a suggestion - -The following steps should serve as a rough guide to add suggestions to -`suggest-tests` (very welcome!): - -1. Determine the rules for your suggestion. Is it simple and operates only on a - single path or does it match globs? Does it need fine-grained control over - the resulting command or does "one size fit all"? -2. Based on the previous step, decide if your suggestion should be implemented - as either static or dynamic. -3. Implement the suggestion. If it is dynamic then a test is highly recommended, - to verify that your logic is correct and to give an example of the - suggestion. See the - [tests.rs](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/tests.rs) - file. -4. Open a PR implementing your suggestion. **(TODO: add example PR)** diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md index e80ff85edad1..b173bf82b440 100644 --- a/src/doc/rustc/src/platform-support/netbsd.md +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -32,10 +32,11 @@ are built for NetBSD 8.x but also work on newer OS versions). ## Target Maintainers [@he32](https://github.com/he32) +[@0323pin](https://github.com/0323pin) Further contacts: -- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust +- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust188/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust. Note that we have the convention of having multiple rust versions active in pkgsrc-wip at any one time, so the version number is part of the directory name, and from time to time old versions are culled so this is not a fully "stable" link. - [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc. - [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index d3da1f353e24..28a228d54645 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -73,7 +73,6 @@ complete -c x -n "__fish_x_needs_command" -a "dist" -d 'Build distribution artif complete -c x -n "__fish_x_needs_command" -a "install" -d 'Install distribution artifacts' complete -c x -n "__fish_x_needs_command" -a "run" -d 'Run tools contained in this repository' complete -c x -n "__fish_x_needs_command" -a "setup" -d 'Set up the environment for development' -complete -c x -n "__fish_x_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x -n "__fish_x_needs_command" -a "vendor" -d 'Vendor dependencies' complete -c x -n "__fish_x_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x -n "__fish_x_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F @@ -599,42 +598,6 @@ complete -c x -n "__fish_x_using_subcommand setup" -l enable-bolt-settings -d 'E complete -c x -n "__fish_x_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l host -d 'host targets to build' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l target -d 'target targets to build' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" -complete -c x -n "__fish_x_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r -complete -c x -n "__fish_x_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l run -d 'run suggested tests' -complete -c x -n "__fish_x_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' -complete -c x -n "__fish_x_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation' -complete -c x -n "__fish_x_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones' -complete -c x -n "__fish_x_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything' -complete -c x -n "__fish_x_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' -complete -c x -n "__fish_x_using_subcommand suggest" -l json-output -d 'use message-format=json' -complete -c x -n "__fish_x_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)' -complete -c x -n "__fish_x_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' -complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' -complete -c x -n "__fish_x_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' -complete -c x -n "__fish_x_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' -complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index b5b59c58bbae..0c9b38282731 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') - [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`') break @@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } - 'x;suggest' { - [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') - [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') - [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') - [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') - [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') - [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') - [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format') - [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') - [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') - [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') - [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') - [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') - [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') - [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') - [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') - [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') - [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') - [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') - [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests') - [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') - [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') - [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') - [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json') - [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)') - [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') - [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') - [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') - [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - break - } 'x;vendor' { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index da7680a879de..43ae7424e27b 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -73,7 +73,6 @@ complete -c x.py -n "__fish_x.py_needs_command" -a "dist" -d 'Build distribution complete -c x.py -n "__fish_x.py_needs_command" -a "install" -d 'Install distribution artifacts' complete -c x.py -n "__fish_x.py_needs_command" -a "run" -d 'Run tools contained in this repository' complete -c x.py -n "__fish_x.py_needs_command" -a "setup" -d 'Set up the environment for development' -complete -c x.py -n "__fish_x.py_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x.py -n "__fish_x.py_needs_command" -a "vendor" -d 'Vendor dependencies' complete -c x.py -n "__fish_x.py_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x.py -n "__fish_x.py_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F @@ -599,42 +598,6 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l enable-bolt-settings complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l host -d 'host targets to build' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l target -d 'target targets to build' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l run -d 'run suggested tests' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l json-output -d 'use message-format=json' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 3fc8e7d5bbd9..4311e383d640 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') - [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`') break @@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } - 'x.py;suggest' { - [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') - [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') - [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') - [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') - [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') - [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') - [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format') - [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') - [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') - [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') - [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') - [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') - [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') - [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') - [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') - [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') - [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') - [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') - [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests') - [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') - [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') - [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') - [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json') - [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)') - [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') - [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') - [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') - [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - break - } 'x.py;vendor' { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 8f13de282fb7..f31bdb58dc44 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -54,9 +54,6 @@ _x.py() { x.py,setup) cmd="x.py__setup" ;; - x.py,suggest) - cmd="x.py__suggest" - ;; x.py,test) cmd="x.py__test" ;; @@ -85,7 +82,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3877,192 +3874,6 @@ _x.py() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - x.py__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --config) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --build-dir) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --build) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --host) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --target) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --exclude) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --skip) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --rustc-error-format) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --on-fail) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage-std) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --src) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --jobs) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - -j) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --warnings) - COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) - return 0 - ;; - --rust-profile-generate) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --rust-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --llvm-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --reproducible-artifact) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --set) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --ci) - COMPREPLY=($(compgen -W "true false" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; x.py__test) opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 60ce90021162..aff35b31e212 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; -(suggest) -_arguments "${_arguments_options[@]}" : \ -'--config=[TOML configuration file for build]:FILE:_files' \ -'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[host target of the stage0 compiler]:BUILD:' \ -'--host=[host targets to build]:HOST:' \ -'--target=[target targets to build]:TARGET:' \ -'*--exclude=[build paths to exclude]:PATH:_files' \ -'*--skip=[build paths to skip]:PATH:_files' \ -'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \ -'--on-fail=[command to run on failure]:CMD:_cmdstring' \ -'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \ -'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'--src=[path to the root of the rust checkout]:DIR:_files -/' \ -'-j+[number of jobs to run in parallel]:JOBS:' \ -'--jobs=[number of jobs to run in parallel]:JOBS:' \ -'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ -'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ -'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ -'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ -'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ -'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ -'*--set=[override options in bootstrap.toml]:section.option=value:' \ -'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ -'--run[run suggested tests]' \ -'*-v[use verbose output (-vv for very verbose)]' \ -'*--verbose[use verbose output (-vv for very verbose)]' \ -'-i[use incremental compilation]' \ -'--incremental[use incremental compilation]' \ -'--include-default-paths[include default paths in addition to the provided ones]' \ -'--dry-run[dry run; don'\''t build anything]' \ -'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ -'--json-output[use message-format=json]' \ -'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \ -'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ -'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ -'--enable-bolt-settings[Enable BOLT link flags]' \ -'--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::paths -- paths for the subcommand:_files' \ -&& ret=0 -;; (vendor) _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ @@ -1120,7 +1075,6 @@ _x.py_commands() { 'install:Install distribution artifacts' \ 'run:Run tools contained in this repository' \ 'setup:Set up the environment for development' \ -'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \ ) @@ -1227,11 +1181,6 @@ _x.py__setup_commands() { local commands; commands=() _describe -t commands 'x.py setup commands' commands "$@" } -(( $+functions[_x.py__suggest_commands] )) || -_x.py__suggest_commands() { - local commands; commands=() - _describe -t commands 'x.py suggest commands' commands "$@" -} (( $+functions[_x.py__test_commands] )) || _x.py__test_commands() { local commands; commands=() diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index f6ecf4cebf49..927d8f7661cd 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -54,9 +54,6 @@ _x() { x,setup) cmd="x__setup" ;; - x,suggest) - cmd="x__suggest" - ;; x,test) cmd="x__test" ;; @@ -85,7 +82,7 @@ _x() { case "${cmd}" in x) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3877,192 +3874,6 @@ _x() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - x__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --config) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --build-dir) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --build) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --host) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --target) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --exclude) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --skip) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --rustc-error-format) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --on-fail) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage-std) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --src) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --jobs) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - -j) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --warnings) - COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) - return 0 - ;; - --rust-profile-generate) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --rust-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --llvm-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --reproducible-artifact) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --set) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --ci) - COMPREPLY=($(compgen -W "true false" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; x__test) opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 452a26fef07e..28ad00f3a0de 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; -(suggest) -_arguments "${_arguments_options[@]}" : \ -'--config=[TOML configuration file for build]:FILE:_files' \ -'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[host target of the stage0 compiler]:BUILD:' \ -'--host=[host targets to build]:HOST:' \ -'--target=[target targets to build]:TARGET:' \ -'*--exclude=[build paths to exclude]:PATH:_files' \ -'*--skip=[build paths to skip]:PATH:_files' \ -'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \ -'--on-fail=[command to run on failure]:CMD:_cmdstring' \ -'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \ -'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'--src=[path to the root of the rust checkout]:DIR:_files -/' \ -'-j+[number of jobs to run in parallel]:JOBS:' \ -'--jobs=[number of jobs to run in parallel]:JOBS:' \ -'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ -'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ -'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ -'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ -'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ -'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ -'*--set=[override options in bootstrap.toml]:section.option=value:' \ -'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ -'--run[run suggested tests]' \ -'*-v[use verbose output (-vv for very verbose)]' \ -'*--verbose[use verbose output (-vv for very verbose)]' \ -'-i[use incremental compilation]' \ -'--incremental[use incremental compilation]' \ -'--include-default-paths[include default paths in addition to the provided ones]' \ -'--dry-run[dry run; don'\''t build anything]' \ -'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ -'--json-output[use message-format=json]' \ -'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \ -'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ -'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ -'--enable-bolt-settings[Enable BOLT link flags]' \ -'--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::paths -- paths for the subcommand:_files' \ -&& ret=0 -;; (vendor) _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ @@ -1120,7 +1075,6 @@ _x_commands() { 'install:Install distribution artifacts' \ 'run:Run tools contained in this repository' \ 'setup:Set up the environment for development' \ -'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \ ) @@ -1227,11 +1181,6 @@ _x__setup_commands() { local commands; commands=() _describe -t commands 'x setup commands' commands "$@" } -(( $+functions[_x__suggest_commands] )) || -_x__suggest_commands() { - local commands; commands=() - _describe -t commands 'x suggest commands' commands "$@" -} (( $+functions[_x__test_commands] )) || _x__test_commands() { local commands; commands=() diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3ecd41db2ddc..20babc6168b9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -759,79 +759,48 @@ impl Item { Some(tcx.visibility(def_id)) } - fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { - const ALLOWED_ATTRIBUTES: &[Symbol] = - &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; + /// Get a list of attributes excluding `#[repr]` to display. + /// + /// Only used by the HTML output-format. + fn attributes_without_repr(&self) -> Vec { self.attrs .other_attrs .iter() - .filter_map(|attr| { - if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr { + .filter_map(|attr| match attr { + hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { Some(format!("#[link_section = \"{name}\"]")) } - // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing. - // It is also used by cargo-semver-checks. - else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr { + hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { Some("#[no_mangle]".to_string()) - } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr - { - Some(format!("#[export_name = \"{name}\"]")) - } else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr { - Some("#[non_exhaustive]".to_string()) - } else if is_json { - match attr { - // rustdoc-json stores this in `Item::deprecation`, so we - // don't want it it `Item::attrs`. - hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None, - // We have separate pretty-printing logic for `#[repr(..)]` attributes. - hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None, - // target_feature is special-cased because cargo-semver-checks uses it - hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => { - let mut output = String::new(); - for (i, (feature, _)) in features.iter().enumerate() { - if i != 0 { - output.push_str(", "); - } - output.push_str(&format!("enable=\"{}\"", feature.as_str())); - } - Some(format!("#[target_feature({output})]")) - } - hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => { - Some("#[automatically_derived]".to_string()) - } - _ => Some({ - let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); - assert_eq!(s.pop(), Some('\n')); - s - }), - } - } else { - if !attr.has_any_name(ALLOWED_ATTRIBUTES) { - return None; - } - Some( - rustc_hir_pretty::attribute_to_string(&tcx, attr) - .replace("\\\n", "") - .replace('\n', "") - .replace(" ", " "), - ) } + hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { + Some(format!("#[export_name = \"{name}\"]")) + } + hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { + Some("#[non_exhaustive]".to_string()) + } + _ => None, }) .collect() } - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { - let mut attrs = self.attributes_without_repr(tcx, is_json); + /// Get a list of attributes to display on this item. + /// + /// Only used by the HTML output-format. + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec { + let mut attrs = self.attributes_without_repr(); - if let Some(repr_attr) = self.repr(tcx, cache, is_json) { + if let Some(repr_attr) = self.repr(tcx, cache) { attrs.push(repr_attr); } attrs } /// Returns a stringified `#[repr(...)]` attribute. - pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option { - repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json) + /// + /// Only used by the HTML output-format. + pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option { + repr_attributes(tcx, cache, self.def_id()?, self.type_()) } pub fn is_doc_hidden(&self) -> bool { @@ -843,12 +812,14 @@ impl Item { } } +/// Return a string representing the `#[repr]` attribute if present. +/// +/// Only used by the HTML output-format. pub(crate) fn repr_attributes( tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId, item_type: ItemType, - is_json: bool, ) -> Option { use rustc_abi::IntegerType; @@ -865,7 +836,6 @@ pub(crate) fn repr_attributes( // Render `repr(transparent)` iff the non-1-ZST field is public or at least one // field is public in case all fields are 1-ZST fields. let render_transparent = cache.document_private - || is_json || adt .all_fields() .find(|field| { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 70f3f54e4c05..06de4944d97d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1191,7 +1191,7 @@ fn render_assoc_item( // a whitespace prefix and newline. fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display { fmt::from_fn(move |f| { - for a in it.attributes(cx.tcx(), cx.cache(), false) { + for a in it.attributes(cx.tcx(), cx.cache()) { writeln!(f, "{prefix}{a}")?; } Ok(()) @@ -1207,7 +1207,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) { // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { - for attr in it.attributes(cx.tcx(), cx.cache(), false) { + for attr in it.attributes(cx.tcx(), cx.cache()) { render_code_attribute(CodeAttribute(attr), w); } } @@ -1219,7 +1219,7 @@ fn render_repr_attributes_in_code( def_id: DefId, item_type: ItemType, ) { - if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) { + if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { render_code_attribute(CodeAttribute(repr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e33bdc0db32f..667d39e9bc2f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1487,12 +1487,11 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { self.cx.cache(), self.def_id, ItemType::Union, - false, ) { writeln!(f, "{repr}")?; }; } else { - for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) { + for a in self.it.attributes(self.cx.tcx(), self.cx.cache()) { writeln!(f, "{a}")?; } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index e7163bead92e..0a84d8caa30f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -5,10 +5,12 @@ use rustc_abi::ExternAbi; use rustc_ast::ast; use rustc_attr_data_structures::{self as attrs, DeprecatedSince}; +use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_hir::{HeaderSafety, Safety}; use rustc_metadata::rendered_const; +use rustc_middle::ty::TyCtxt; use rustc_middle::{bug, ty}; use rustc_span::{Pos, kw, sym}; use rustdoc_json_types::*; @@ -39,7 +41,12 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes(self.tcx, &self.cache, true); + let attrs = item + .attrs + .other_attrs + .iter() + .filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx)) + .collect(); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; @@ -886,3 +893,93 @@ impl FromClean for ItemKind { } } } + +/// Maybe convert a attribute from hir to json. +/// +/// Returns `None` if the attribute shouldn't be in the output. +fn maybe_from_hir_attr( + attr: &hir::Attribute, + item_id: ItemId, + tcx: TyCtxt<'_>, +) -> Option { + use attrs::AttributeKind as AK; + + let kind = match attr { + hir::Attribute::Parsed(kind) => kind, + + hir::Attribute::Unparsed(_) => { + // FIXME: We should handle `#[doc(hidden)]`. + return Some(other_attr(tcx, attr)); + } + }; + + Some(match kind { + AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation. + AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), + + AK::MustUse { reason, span: _ } => { + Attribute::MustUse { reason: reason.map(|s| s.to_string()) } + } + AK::Repr { .. } => repr_attr( + tcx, + item_id.as_def_id().expect("all items that could have #[repr] have a DefId"), + ), + AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()), + AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()), + AK::TargetFeature(features, _span) => Attribute::TargetFeature { + enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(), + }, + + AK::NoMangle(_) => Attribute::NoMangle, + AK::NonExhaustive(_) => Attribute::NonExhaustive, + AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived, + + _ => other_attr(tcx, attr), + }) +} + +fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute { + let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); + assert_eq!(s.pop(), Some('\n')); + Attribute::Other(s) +} + +fn repr_attr(tcx: TyCtxt<'_>, def_id: DefId) -> Attribute { + let repr = tcx.adt_def(def_id).repr(); + + let kind = if repr.c() { + ReprKind::C + } else if repr.transparent() { + ReprKind::Transparent + } else if repr.simd() { + ReprKind::Simd + } else { + ReprKind::Rust + }; + + let align = repr.align.map(|a| a.bytes()); + let packed = repr.pack.map(|p| p.bytes()); + let int = repr.int.map(format_integer_type); + + Attribute::Repr(AttributeRepr { kind, align, packed, int }) +} + +fn format_integer_type(it: rustc_abi::IntegerType) -> String { + use rustc_abi::Integer::*; + use rustc_abi::IntegerType::*; + match it { + Pointer(true) => "isize", + Pointer(false) => "usize", + Fixed(I8, true) => "i8", + Fixed(I8, false) => "u8", + Fixed(I16, true) => "i16", + Fixed(I16, false) => "u16", + Fixed(I32, true) => "i32", + Fixed(I32, false) => "u32", + Fixed(I64, true) => "i64", + Fixed(I64, false) => "u64", + Fixed(I128, true) => "i128", + Fixed(I128, false) => "u128", + } + .to_owned() +} diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 0e72ddd9db1e..6235b0e8576f 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of no_mangle attributes changed -pub const FORMAT_VERSION: u32 = 53; +// Latest feature: Structured Attributes +pub const FORMAT_VERSION: u32 = 54; /// The root of the emitted JSON blob. /// @@ -195,13 +195,94 @@ pub struct Item { /// - `#[repr(C)]` and other reprs also appear as themselves, /// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`. /// Multiple repr attributes on the same item may be combined into an equivalent single attr. - pub attrs: Vec, + pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, /// The type-specific fields describing this item. pub inner: ItemEnum, } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +/// An attribute, e.g. `#[repr(C)]` +/// +/// This doesn't include: +/// - `#[doc = "Doc Comment"]` or `/// Doc comment`. These are in [`Item::docs`] instead. +/// - `#[deprecated]`. These are in [`Item::deprecation`] instead. +pub enum Attribute { + /// `#[non_exhaustive]` + NonExhaustive, + + /// `#[must_use]` + MustUse { reason: Option }, + + /// `#[export_name = "name"]` + ExportName(String), + + /// `#[link_section = "name"]` + LinkSection(String), + + /// `#[automatically_derived]` + AutomaticallyDerived, + + /// `#[repr]` + Repr(AttributeRepr), + + /// `#[no_mangle]` + NoMangle, + + /// #[target_feature(enable = "feature1", enable = "feature2")] + TargetFeature { enable: Vec }, + + /// Something else. + /// + /// Things here are explicitly *not* covered by the [`FORMAT_VERSION`] + /// constant, and may change without bumping the format version. + /// + /// As an implementation detail, this is currently either: + /// 1. A HIR debug printing, like `"#[attr = Optimize(Speed)]"` + /// 2. The attribute as it appears in source form, like + /// `"#[optimize(speed)]"`. + Other(String), +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +/// The contents of a `#[repr(...)]` attribute. +/// +/// Used in [`Attribute::Repr`]. +pub struct AttributeRepr { + /// The representation, e.g. `#[repr(C)]`, `#[repr(transparent)]` + pub kind: ReprKind, + + /// Alignment in bytes, if explicitly specified by `#[repr(align(...)]`. + pub align: Option, + /// Alignment in bytes, if explicitly specified by `#[repr(packed(...)]]`. + pub packed: Option, + + /// The integer type for an enum descriminant, if explicitly specified. + /// + /// e.g. `"i32"`, for `#[repr(C, i32)]` + pub int: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +/// The kind of `#[repr]`. +/// +/// See [AttributeRepr::kind]`. +pub enum ReprKind { + /// `#[repr(Rust)]` + /// + /// Also the default. + Rust, + /// `#[repr(C)]` + C, + /// `#[repr(transparent)] + Transparent, + /// `#[repr(simd)]` + Simd, +} + /// A range of source code. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Span { @@ -1343,7 +1424,7 @@ pub struct Static { /// Is the static `unsafe`? /// - /// This is only true if it's in an `extern` block, and not explicity marked + /// This is only true if it's in an `extern` block, and not explicitly marked /// as `safe`. /// /// ```rust diff --git a/src/tools/cargo b/src/tools/cargo index eabb4cd923de..6833aa715d72 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit eabb4cd923deb73e714f7ad3f5234d68ca284dbe +Subproject commit 6833aa715d724437dc1247d0166afe314ab6854e diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 6bf968a3132e..93133ea0bfd2 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -971,6 +971,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-mips64", "only-msp430", "only-msvc", + "only-musl", "only-nightly", "only-nvptx64", "only-powerpc", diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 67f27e7aa2c7..3f10132b684b 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -7f2065a4bae1faed5bab928c670964eafbf43b55 +fd2eb391d032181459773f3498c17b198513e0d0 diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 35d3e7e647cc..ccfff7fa94bd 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -13,7 +13,7 @@ use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout}; use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy}; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs new file mode 100644 index 000000000000..107a3db91d85 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs @@ -0,0 +1,6 @@ +fn main() { + let v: Vec = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; //~ ERROR: before the beginning of the allocation + panic!("this should never print: {}", x); +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr new file mode 100644 index 000000000000..5c37caa1ebf0 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC-0x5 which points to before the beginning of the allocation + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let v: Vec = vec![1, 2]; + | ^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs new file mode 100644 index 000000000000..0085e2af3673 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs @@ -0,0 +1,6 @@ +fn main() { + let v = [0i8; 4]; + let x = &v as *const i8; + let x = unsafe { x.wrapping_offset(-1).offset(-1) }; //~ERROR: before the beginning of the allocation + panic!("this should never print: {:?}", x); +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr new file mode 100644 index 000000000000..495aaf8d40ee --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC-0x1 which points to before the beginning of the allocation + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let x = unsafe { x.wrapping_offset(-1).offset(-1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let v = [0i8; 4]; + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index bda08423487b..b9741431b503 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -335,7 +335,9 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { std::process::exit(code); } else { println!("died due to signal {}", code); - std::process::exit(3); + // Behave like bash and other tools and exit with 128 + the signal + // number. That way we can avoid special case code in other places. + std::process::exit(128 + code); } } diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs index e4d244e14a4a..0e11360bd5a0 100644 --- a/src/tools/run-make-support/src/symbols.rs +++ b/src/tools/run-make-support/src/symbols.rs @@ -1,6 +1,7 @@ +use std::collections::BTreeSet; use std::path::Path; -use object::{self, Object, ObjectSymbol, SymbolIterator}; +use object::{self, Object, ObjectSymbol}; /// Given an [`object::File`], find the exported dynamic symbol names via /// [`object::Object::exports`]. This does not distinguish between which section the symbols appear @@ -14,47 +15,180 @@ pub fn exported_dynamic_symbol_names<'file>(file: &'file object::File<'file>) -> .collect() } -/// Iterate through the symbols in an object file. See [`object::Object::symbols`]. +/// Check an object file's symbols for any matching **substrings**. That is, if an object file +/// contains a symbol named `hello_world`, it will be matched against a provided `substrings` of +/// `["hello", "bar"]`. +/// +/// Returns `true` if **any** of the symbols found in the object file at `path` contain a +/// **substring** listed in `substrings`. /// /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be /// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// On Windows MSVC, the binary (e.g. `main.exe`) does not contain the symbols, but in the separate +/// PDB file instead. Furthermore, you will need to use [`crate::llvm::llvm_pdbutil`] as `object` +/// crate does not handle PDB files. #[track_caller] -pub fn with_symbol_iter(path: P, func: F) -> R +pub fn object_contains_any_symbol_substring(path: P, substrings: &[S]) -> bool where P: AsRef, - F: FnOnce(&mut SymbolIterator<'_, '_>) -> R, + S: AsRef, { let path = path.as_ref(); let blob = crate::fs::read(path); - let f = object::File::parse(&*blob) + let obj = object::File::parse(&*blob) .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); - let mut iter = f.symbols(); - func(&mut iter) + let substrings = substrings.iter().map(|s| s.as_ref()).collect::>(); + for sym in obj.symbols() { + for substring in &substrings { + if sym.name_bytes().unwrap().windows(substring.len()).any(|x| x == substring.as_bytes()) + { + return true; + } + } + } + false } -/// Check an object file's symbols for substrings. +/// Check an object file's symbols for any exact matches against those provided in +/// `candidate_symbols`. /// -/// Returns `true` if any of the symbols found in the object file at `path` contain a substring -/// listed in `substrings`. +/// Returns `true` if **any** of the symbols found in the object file at `path` contain an **exact +/// match** against those listed in `candidate_symbols`. Take care to account for (1) platform +/// differences and (2) calling convention and symbol decorations differences. /// /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be /// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. #[track_caller] -pub fn any_symbol_contains(path: impl AsRef, substrings: &[&str]) -> bool { - with_symbol_iter(path, |syms| { - for sym in syms { - for substring in substrings { - if sym - .name_bytes() - .unwrap() - .windows(substring.len()) - .any(|x| x == substring.as_bytes()) - { - eprintln!("{:?} contains {}", sym, substring); - return true; - } +pub fn object_contains_any_symbol(path: P, candidate_symbols: &[S]) -> bool +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()).collect::>(); + for sym in obj.symbols() { + for candidate_symbol in &candidate_symbols { + if sym.name_bytes().unwrap() == candidate_symbol.as_bytes() { + return true; } } - false - }) + } + false +} + +#[derive(Debug, PartialEq)] +pub enum ContainsAllSymbolSubstringsOutcome<'a> { + Ok, + MissingSymbolSubstrings(BTreeSet<&'a str>), +} + +/// Check an object file's symbols for presence of all of provided **substrings**. That is, if an +/// object file contains symbols `["hello", "goodbye", "world"]`, it will be matched against a list +/// of `substrings` of `["he", "go"]`. In this case, `he` is a substring of `hello`, and `go` is a +/// substring of `goodbye`, so each of `substrings` was found. +/// +/// Returns `true` if **all** `substrings` were present in the names of symbols for the given object +/// file (as substrings of symbol names). +/// +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. +#[track_caller] +pub fn object_contains_all_symbol_substring<'s, P, S>( + path: P, + substrings: &'s [S], +) -> ContainsAllSymbolSubstringsOutcome<'s> +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let substrings = substrings.iter().map(|s| s.as_ref()); + let mut unmatched_symbol_substrings = BTreeSet::from_iter(substrings); + unmatched_symbol_substrings.retain(|unmatched_symbol_substring| { + for sym in obj.symbols() { + if sym + .name_bytes() + .unwrap() + .windows(unmatched_symbol_substring.len()) + .any(|x| x == unmatched_symbol_substring.as_bytes()) + { + return false; + } + } + + true + }); + + if unmatched_symbol_substrings.is_empty() { + ContainsAllSymbolSubstringsOutcome::Ok + } else { + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(unmatched_symbol_substrings) + } +} + +#[derive(Debug, PartialEq)] +pub enum ContainsAllSymbolsOutcome<'a> { + Ok, + MissingSymbols(BTreeSet<&'a str>), +} + +/// Check an object file contains all symbols provided in `candidate_symbols`. +/// +/// Returns `true` if **all** of the symbols in `candidate_symbols` are found within the object file +/// at `path` by **exact match**. Take care to account for (1) platform differences and (2) calling +/// convention and symbol decorations differences. +/// +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. +#[track_caller] +pub fn object_contains_all_symbols( + path: P, + candidate_symbols: &[S], +) -> ContainsAllSymbolsOutcome<'_> +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()); + let mut unmatched_symbols = BTreeSet::from_iter(candidate_symbols); + unmatched_symbols.retain(|unmatched_symbol| { + for sym in obj.symbols() { + if sym.name_bytes().unwrap() == unmatched_symbol.as_bytes() { + return false; + } + } + + true + }); + + if unmatched_symbols.is_empty() { + ContainsAllSymbolsOutcome::Ok + } else { + ContainsAllSymbolsOutcome::MissingSymbols(unmatched_symbols) + } } diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 050ddf47baef..27798d6aeb0b 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -885,9 +885,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.51" +version = "0.4.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328" +checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 69c0cfaf5c99..c7c6e39f1577 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.51" +version = "0.4.52" default-features = false features = ["search"] diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml deleted file mode 100644 index d6f86078d7ef..000000000000 --- a/src/tools/suggest-tests/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "suggest-tests" -version = "0.1.0" -edition = "2021" - -[dependencies] -glob = "0.3.0" -build_helper = { version = "0.1.0", path = "../../build_helper" } diff --git a/src/tools/suggest-tests/src/dynamic_suggestions.rs b/src/tools/suggest-tests/src/dynamic_suggestions.rs deleted file mode 100644 index f09720f1c91f..000000000000 --- a/src/tools/suggest-tests/src/dynamic_suggestions.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::path::Path; - -use crate::Suggestion; - -type DynamicSuggestion = fn(&Path) -> Vec; - -pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[ - |path: &Path| -> Vec { - if path.starts_with("compiler/") || path.starts_with("library/") { - let path = path.components().take(2).collect::>(); - - vec![Suggestion::with_single_path( - "test", - None, - &format!( - "{}/{}", - path[0].as_os_str().to_str().unwrap(), - path[1].as_os_str().to_str().unwrap() - ), - )] - } else { - Vec::new() - } - }, - |path: &Path| -> Vec { - if path.starts_with("compiler/rustc_pattern_analysis") { - vec![Suggestion::new("test", None, &["tests/ui", "--test-args", "pattern"])] - } else { - Vec::new() - } - }, -]; diff --git a/src/tools/suggest-tests/src/lib.rs b/src/tools/suggest-tests/src/lib.rs deleted file mode 100644 index cc1288c6b72e..000000000000 --- a/src/tools/suggest-tests/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::fmt::{self, Display}; -use std::path::Path; - -use dynamic_suggestions::DYNAMIC_SUGGESTIONS; -use glob::Pattern; -use static_suggestions::static_suggestions; - -mod dynamic_suggestions; -mod static_suggestions; - -#[cfg(test)] -mod tests; - -macro_rules! sug { - ($cmd:expr) => { - Suggestion::new($cmd, None, &[]) - }; - - ($cmd:expr, $paths:expr) => { - Suggestion::new($cmd, None, $paths.as_slice()) - }; - - ($cmd:expr, $stage:expr, $paths:expr) => { - Suggestion::new($cmd, Some($stage), $paths.as_slice()) - }; -} - -pub(crate) use sug; - -pub fn get_suggestions>(modified_files: &[T]) -> Vec { - let mut suggestions = Vec::new(); - - // static suggestions - for (globs, sugs) in static_suggestions().iter() { - let globs = globs - .iter() - .map(|glob| Pattern::new(glob).expect("Found invalid glob pattern!")) - .collect::>(); - let matches_some_glob = |file: &str| globs.iter().any(|glob| glob.matches(file)); - - if modified_files.iter().map(AsRef::as_ref).any(matches_some_glob) { - suggestions.extend_from_slice(sugs); - } - } - - // dynamic suggestions - for sug in DYNAMIC_SUGGESTIONS { - for file in modified_files { - let sugs = sug(Path::new(file.as_ref())); - - suggestions.extend_from_slice(&sugs); - } - } - - suggestions.sort(); - suggestions.dedup(); - - suggestions -} - -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] -pub struct Suggestion { - pub cmd: String, - pub stage: Option, - pub paths: Vec, -} - -impl Suggestion { - pub fn new(cmd: &str, stage: Option, paths: &[&str]) -> Self { - Self { cmd: cmd.to_owned(), stage, paths: paths.iter().map(|p| p.to_string()).collect() } - } - - pub fn with_single_path(cmd: &str, stage: Option, path: &str) -> Self { - Self::new(cmd, stage, &[path]) - } -} - -impl Display for Suggestion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "{} ", self.cmd)?; - - for path in &self.paths { - write!(f, "{} ", path)?; - } - - if let Some(stage) = self.stage { - write!(f, "{}", stage)?; - } else { - // write a sentinel value here (in place of a stage) to be consumed - // by the shim in bootstrap, it will be read and ignored. - write!(f, "N/A")?; - } - - Ok(()) - } -} diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs deleted file mode 100644 index d84f8e9fa1ba..000000000000 --- a/src/tools/suggest-tests/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::process::ExitCode; - -use build_helper::git::{GitConfig, get_git_modified_files}; -use suggest_tests::get_suggestions; - -fn main() -> ExitCode { - let modified_files = get_git_modified_files( - &GitConfig { - nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"), - git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"), - }, - None, - &Vec::new(), - ); - let modified_files = match modified_files { - Ok(files) => files, - Err(err) => { - eprintln!("Could not get modified files from git: \"{err}\""); - return ExitCode::FAILURE; - } - }; - - let suggestions = get_suggestions(&modified_files); - - for sug in &suggestions { - println!("{sug}"); - } - - ExitCode::SUCCESS -} - -fn env(key: &str) -> String { - match std::env::var(key) { - Ok(var) => var, - Err(err) => { - eprintln!("suggest-tests: failed to read environment variable {key}: {err}"); - std::process::exit(1); - } - } -} diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs deleted file mode 100644 index d363d583b546..000000000000 --- a/src/tools/suggest-tests/src/static_suggestions.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::sync::OnceLock; - -use crate::{Suggestion, sug}; - -// FIXME: perhaps this could use `std::lazy` when it is stabilized -macro_rules! static_suggestions { - ($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => { - pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec)] - { - static S: OnceLock, Vec)>> = OnceLock::new(); - S.get_or_init(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*]) - } - } -} - -static_suggestions! { - ["*.md"] => [ - sug!("test", 0, ["linkchecker"]), - ], - - ["compiler/*"] => [ - sug!("check"), - sug!("test", 1, ["tests/ui", "tests/run-make"]), - ], - - ["compiler/rustc_mir_transform/*"] => [ - sug!("test", 1, ["mir-opt"]), - ], - - [ - "compiler/rustc_mir_transform/src/coverage/*", - "compiler/rustc_codegen_llvm/src/coverageinfo/*", - ] => [ - sug!("test", 1, ["coverage"]), - ], - - ["src/librustdoc/*"] => [ - sug!("test", 1, ["rustdoc"]), - ], -} diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs deleted file mode 100644 index b4149136fa30..000000000000 --- a/src/tools/suggest-tests/src/tests.rs +++ /dev/null @@ -1,21 +0,0 @@ -macro_rules! sugg_test { - ( $( $name:ident: $paths:expr => $suggestions:expr ),* ) => { - $( - #[test] - fn $name() { - let suggestions = crate::get_suggestions(&$paths).into_iter().map(|s| s.to_string()).collect::>(); - assert_eq!(suggestions, $suggestions); - } - )* - }; -} - -sugg_test! { - test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] => - ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test tests/ui tests/run-make 1"], - - test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"], - - test_rustdoc_and_libstd: ["src/librustdoc/src/lib.rs", "library/std/src/lib.rs"] => - ["test library/std N/A", "test rustdoc 1"] -} diff --git a/src/tools/tidy/src/filenames.rs b/src/tools/tidy/src/filenames.rs new file mode 100644 index 000000000000..53115f4eaa41 --- /dev/null +++ b/src/tools/tidy/src/filenames.rs @@ -0,0 +1,40 @@ +//! Tidy check to ensure that there are no filenames containing forbidden characters +//! checked into the source tree by accident: +//! - Non-UTF8 filenames +//! - Control characters such as CR or TAB +//! - Filenames containing ":" as they are not supported on Windows +//! +//! Only files added to git are checked, as it may be acceptable to have temporary +//! invalid filenames in the local directory during development. + +use std::path::Path; +use std::process::Command; + +pub fn check(root_path: &Path, bad: &mut bool) { + let stat_output = Command::new("git") + .arg("-C") + .arg(root_path) + .args(["ls-files", "-z"]) + .output() + .unwrap() + .stdout; + for filename in stat_output.split(|&b| b == 0) { + match str::from_utf8(filename) { + Err(_) => tidy_error!( + bad, + r#"non-UTF8 file names are not supported: "{}""#, + String::from_utf8_lossy(filename), + ), + Ok(name) if name.chars().any(|c| c.is_control()) => tidy_error!( + bad, + r#"control characters are not supported in file names: "{}""#, + String::from_utf8_lossy(filename), + ), + Ok(name) if name.contains(':') => tidy_error!( + bad, + r#"":" is not supported in file names because of Windows compatibility: "{name}""#, + ), + _ => (), + } + } +} diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index cac4dba2b49d..8b57db23d01c 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2338,7 +2338,6 @@ ui/issues/issue-50415.rs ui/issues/issue-50442.rs ui/issues/issue-50471.rs ui/issues/issue-50518.rs -ui/issues/issue-50571.rs ui/issues/issue-50581.rs ui/issues/issue-50582.rs ui/issues/issue-50585.rs diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 77855392b4da..ade4055b5bd1 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -167,6 +167,7 @@ pub mod error_codes; pub mod ext_tool_checks; pub mod extdeps; pub mod features; +pub mod filenames; pub mod fluent_alphabetical; pub mod fluent_period; mod fluent_used; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index a67f7a511b59..0f1116a632e2 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -155,6 +155,8 @@ fn main() { check!(triagebot, &root_path); + check!(filenames, &root_path); + let collected = { drain_handles(&mut handles); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index b1ace74e5bd2..7e295731c56b 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1619; +const ISSUES_ENTRY_LIMIT: u32 = 1616; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs new file mode 100644 index 000000000000..73826214aac6 --- /dev/null +++ b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs @@ -0,0 +1,92 @@ +//! `run_make_support::symbols` helpers self test. + +// Only intended as a basic smoke test, does not try to account for platform or calling convention +// specific symbol decorations. +//@ only-x86_64-unknown-linux-gnu +//@ ignore-cross-compile + +use std::collections::BTreeSet; + +use object::{Object, ObjectSymbol}; +use run_make_support::symbols::{ + ContainsAllSymbolSubstringsOutcome, ContainsAllSymbolsOutcome, + object_contains_all_symbol_substring, object_contains_all_symbols, object_contains_any_symbol, + object_contains_any_symbol_substring, +}; +use run_make_support::{object, rfs, rust_lib_name, rustc}; + +fn main() { + rustc().input("sample.rs").emit("obj").edition("2024").run(); + + // `sample.rs` has two `no_mangle` functions, `eszett` and `beta`, in addition to `main`. + // + // These two symbol names and the test substrings used below are carefully picked to make sure + // they do not overlap with `sample` and contain non-hex characters, to avoid accidentally + // matching against CGU names like `sample.dad0f15d00c84e70-cgu.0`. + + let obj_filename = "sample.o"; + let blob = rfs::read(obj_filename); + let obj = object::File::parse(&*blob).unwrap(); + eprintln!("found symbols:"); + for sym in obj.symbols() { + eprintln!("symbol = {}", sym.name().unwrap()); + } + + // `hello` contains `hel` + assert!(object_contains_any_symbol_substring(obj_filename, &["zett"])); + assert!(object_contains_any_symbol_substring(obj_filename, &["zett", "does_not_exist"])); + assert!(!object_contains_any_symbol_substring(obj_filename, &["does_not_exist"])); + + assert!(object_contains_any_symbol(obj_filename, &["eszett"])); + assert!(object_contains_any_symbol(obj_filename, &["eszett", "beta"])); + assert!(!object_contains_any_symbol(obj_filename, &["zett"])); + assert!(!object_contains_any_symbol(obj_filename, &["does_not_exist"])); + + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett"]), + ContainsAllSymbolSubstringsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "bet"]), + ContainsAllSymbolSubstringsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "bet", "does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + + assert_eq!( + object_contains_all_symbols(obj_filename, &["eszett"]), + ContainsAllSymbolsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["eszett", "beta"]), + ContainsAllSymbolsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["zett"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"])) + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["zett", "beta"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"])) + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["does_not_exist"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["does_not_exist"])) + ); +} diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs new file mode 100644 index 000000000000..3566d2997668 --- /dev/null +++ b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +#[unsafe(no_mangle)] +pub extern "C" fn eszett() -> i8 { + 42 +} + +#[unsafe(no_mangle)] +pub extern "C" fn beta() -> u32 { + 1 +} + +fn main() {} diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs index af6ff6c29833..b7f18b384cb0 100644 --- a/tests/run-make/fmt-write-bloat/rmake.rs +++ b/tests/run-make/fmt-write-bloat/rmake.rs @@ -20,7 +20,7 @@ use run_make_support::artifact_names::bin_name; use run_make_support::env::std_debug_assertions_enabled; use run_make_support::rustc; -use run_make_support::symbols::any_symbol_contains; +use run_make_support::symbols::object_contains_any_symbol_substring; fn main() { rustc().input("main.rs").opt().run(); @@ -31,5 +31,5 @@ fn main() { // otherwise, add them to the list of symbols to deny. panic_syms.extend_from_slice(&["panicking", "panic_fmt", "pad_integral", "Display"]); } - assert!(!any_symbol_contains(bin_name("main"), &panic_syms)); + assert!(!object_contains_any_symbol_substring(bin_name("main"), &panic_syms)); } diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs index bcdb84132d3f..456321e2f56c 100644 --- a/tests/run-make/used/rmake.rs +++ b/tests/run-make/used/rmake.rs @@ -8,9 +8,9 @@ // https://rust-lang.github.io/rfcs/2386-used.html use run_make_support::rustc; -use run_make_support::symbols::any_symbol_contains; +use run_make_support::symbols::object_contains_any_symbol_substring; fn main() { rustc().opt_level("3").emit("obj").input("used.rs").run(); - assert!(any_symbol_contains("used.o", &["FOO"])); + assert!(object_contains_any_symbol_substring("used.o", &["FOO"])); } diff --git a/tests/rustdoc-json/attrs/automatically_derived.rs b/tests/rustdoc-json/attrs/automatically_derived.rs index 4e1ab3d145e5..9ba310d3655b 100644 --- a/tests/rustdoc-json/attrs/automatically_derived.rs +++ b/tests/rustdoc-json/attrs/automatically_derived.rs @@ -9,5 +9,5 @@ impl Default for Manual { } } -//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]' +//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["automatically_derived"]' //@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]' diff --git a/tests/rustdoc-json/attrs/cold.rs b/tests/rustdoc-json/attrs/cold.rs index e219345d669c..ec1926e894e4 100644 --- a/tests/rustdoc-json/attrs/cold.rs +++ b/tests/rustdoc-json/attrs/cold.rs @@ -1,3 +1,3 @@ -//@ is "$.index[?(@.name=='cold_fn')].attrs" '["#[attr = Cold]"]' +//@ is "$.index[?(@.name=='cold_fn')].attrs" '[{"other": "#[attr = Cold]"}]' #[cold] pub fn cold_fn() {} diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs index 254e9f6ef5bf..451d9b9eb375 100644 --- a/tests/rustdoc-json/attrs/export_name_2021.rs +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]' #[export_name = "altered"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs index 8129c109306c..7e398db92ab3 100644 --- a/tests/rustdoc-json/attrs/export_name_2024.rs +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -2,8 +2,8 @@ #![no_std] // The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 -// is still `#[export_name = ..]` without the `unsafe` attribute wrapper. +// doesn't mention the `unsafe`. -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]' #[unsafe(export_name = "altered")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs index b9ea6ab1d10c..2aed49a48a5c 100644 --- a/tests/rustdoc-json/attrs/inline.rs +++ b/tests/rustdoc-json/attrs/inline.rs @@ -1,11 +1,11 @@ -//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[attr = Inline(Hint)]"]' +//@ is "$.index[?(@.name=='just_inline')].attrs" '[{"other": "#[attr = Inline(Hint)]"}]' #[inline] pub fn just_inline() {} -//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[attr = Inline(Always)]"]' +//@ is "$.index[?(@.name=='inline_always')].attrs" '[{"other": "#[attr = Inline(Always)]"}]' #[inline(always)] pub fn inline_always() {} -//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[attr = Inline(Never)]"]' +//@ is "$.index[?(@.name=='inline_never')].attrs" '[{"other": "#[attr = Inline(Never)]"}]' #[inline(never)] pub fn inline_never() {} diff --git a/tests/rustdoc-json/attrs/link_section_2021.rs b/tests/rustdoc-json/attrs/link_section_2021.rs index a1312f4210b4..acd8ecd0e30c 100644 --- a/tests/rustdoc-json/attrs/link_section_2021.rs +++ b/tests/rustdoc-json/attrs/link_section_2021.rs @@ -1,6 +1,7 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +//@ count "$.index[?(@.name=='example')].attrs[*]" 1 +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' #[link_section = ".text"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/link_section_2024.rs b/tests/rustdoc-json/attrs/link_section_2024.rs index edb028451a8e..8107493229b5 100644 --- a/tests/rustdoc-json/attrs/link_section_2024.rs +++ b/tests/rustdoc-json/attrs/link_section_2024.rs @@ -4,6 +4,7 @@ // Since the 2024 edition the link_section attribute must use the unsafe qualification. // However, the unsafe qualification is not shown by rustdoc. -//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +//@ count "$.index[?(@.name=='example')].attrs[*]" 1 +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' #[unsafe(link_section = ".text")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index 3ca6f5a75a5a..3f924c5169ca 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[attr = MustUse]"]' +//@ is "$.index[?(@.name=='example')].attrs[*].must_use.reason" null #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[attr = MustUse {reason: \"does nothing if you do not use it\"}]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs[*].must_use.reason" '"does nothing if you do not use it"' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs index 588be7256db5..703dcb56491c 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2021.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]' #[no_mangle] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs index 0d500e20e6c5..8af00eeda6bb 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2024.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 // is still `#[no_mangle]` without the `unsafe` attribute wrapper. -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]' #[unsafe(no_mangle)] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs index b95f1a8171fd..e4e6c8fd53ba 100644 --- a/tests/rustdoc-json/attrs/non_exhaustive.rs +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyEnum')].attrs" '["non_exhaustive"]' #[non_exhaustive] pub enum MyEnum { First, } pub enum NonExhaustiveVariant { - //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + //@ is "$.index[?(@.name=='Variant')].attrs" '["non_exhaustive"]' #[non_exhaustive] Variant(i64), } -//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyStruct')].attrs" '["non_exhaustive"]' #[non_exhaustive] pub struct MyStruct { pub x: i64, diff --git a/tests/rustdoc-json/attrs/optimize.rs b/tests/rustdoc-json/attrs/optimize.rs index 0bed0ad18c31..5988120ab2f7 100644 --- a/tests/rustdoc-json/attrs/optimize.rs +++ b/tests/rustdoc-json/attrs/optimize.rs @@ -1,13 +1,13 @@ #![feature(optimize_attribute)] -//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]' +//@ is "$.index[?(@.name=='speed')].attrs" '[{"other": "#[attr = Optimize(Speed)]"}]' #[optimize(speed)] pub fn speed() {} -//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]' +//@ is "$.index[?(@.name=='size')].attrs" '[{"other": "#[attr = Optimize(Size)]"}]' #[optimize(size)] pub fn size() {} -//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]' +//@ is "$.index[?(@.name=='none')].attrs" '[{"other": "#[attr = Optimize(DoNotOptimize)]"}]' #[optimize(none)] pub fn none() {} diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs index c6debda7f1c9..f9d3417c4857 100644 --- a/tests/rustdoc-json/attrs/repr_align.rs +++ b/tests/rustdoc-json/attrs/repr_align.rs @@ -1,6 +1,7 @@ #![no_std] -//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]' +//@ count "$.index[?(@.name=='Aligned')].attrs[*]" 1 +//@ is "$.index[?(@.name=='Aligned')].attrs[*].repr.align" 4 #[repr(align(4))] pub struct Aligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs index e6219413f308..89dbc16cb2a9 100644 --- a/tests/rustdoc-json/attrs/repr_c.rs +++ b/tests/rustdoc-json/attrs/repr_c.rs @@ -1,16 +1,28 @@ #![no_std] -//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCStruct')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.align" null #[repr(C)] pub struct ReprCStruct(pub i64); -//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCEnum')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.align" null #[repr(C)] pub enum ReprCEnum { First, } -//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCUnion')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.align" null #[repr(C)] pub union ReprCUnion { pub left: i64, diff --git a/tests/rustdoc-json/attrs/repr_c_int_enum.rs b/tests/rustdoc-json/attrs/repr_c_int_enum.rs new file mode 100644 index 000000000000..e90bcf2b5c61 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_c_int_enum.rs @@ -0,0 +1,11 @@ +//@ count "$.index[?(@.name=='Foo')].attrs" 1 +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u8"' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.align" 16 +#[repr(C, u8)] +#[repr(align(16))] +pub enum Foo { + A(bool) = b'A', + B(char) = b'C', +} diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs index 6fe29c5eac09..bd4a8563b6f2 100644 --- a/tests/rustdoc-json/attrs/repr_combination.rs +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -1,35 +1,34 @@ #![no_std] // Combinations of `#[repr(..)]` attributes. -// Rustdoc JSON emits normalized output, regardless of the original source. -//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]' +//@ is "$.index[?(@.name=='ReprCI8')].attrs" '[{"repr":{"align":null,"int":"i8","kind":"c","packed":null}}]' #[repr(C, i8)] pub enum ReprCI8 { First, } -//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]' +//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '[{"repr":{"align":null,"int":"i16","kind":"c","packed":null}}]' #[repr(C)] #[repr(i16)] pub enum SeparateReprCI16 { First, } -//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]' +//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '[{"repr":{"align":null,"int":"usize","kind":"c","packed":null}}]' #[repr(usize, C)] pub enum ReversedReprCUsize { First, } -//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]' +//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":1}}]' #[repr(C, packed)] pub struct ReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' +//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]' #[repr(C)] #[repr(packed(2))] pub struct SeparateReprCPacked { @@ -37,21 +36,21 @@ pub struct SeparateReprCPacked { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' +//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]' #[repr(packed(2), C)] pub struct ReversedReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]' +//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '[{"repr":{"align":16,"int":null,"kind":"c","packed":null}}]' #[repr(C, align(16))] pub struct ReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]' +//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]' #[repr(C)] #[repr(align(2))] pub struct SeparateReprCAlign { @@ -59,25 +58,25 @@ pub struct SeparateReprCAlign { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]' +//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]' #[repr(align(2), C)] pub struct ReversedReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' +//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]' #[repr(C, align(16), isize)] pub enum AlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' +//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]' #[repr(isize, C, align(16))] pub enum ReorderedAlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]' +//@ is "$.index[?(@.name=='Transparent')].attrs" '[{"repr":{"align":null,"int":null,"kind":"transparent","packed":null}}]' #[repr(transparent)] pub struct Transparent(i64); diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs index 9b09f341d4fe..79e17f53ad90 100644 --- a/tests/rustdoc-json/attrs/repr_int_enum.rs +++ b/tests/rustdoc-json/attrs/repr_int_enum.rs @@ -1,18 +1,27 @@ #![no_std] -//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.int" '"i8"' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.packed" null #[repr(i8)] pub enum I8 { First, } -//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.int" '"i32"' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.packed" null #[repr(i32)] pub enum I32 { First, } -//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.int" '"usize"' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.packed" null #[repr(usize)] pub enum Usize { First, diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs index 9f3fd86c4b03..ab573835b45c 100644 --- a/tests/rustdoc-json/attrs/repr_packed.rs +++ b/tests/rustdoc-json/attrs/repr_packed.rs @@ -1,16 +1,18 @@ #![no_std] // Note the normalization: -// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON. +// `#[repr(packed)]` in source becomes `{"repr": {"packed": 1, ...}}` in rustdoc JSON. // -//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]' +//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.packed" 1 +//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.kind" '"rust"' #[repr(packed)] pub struct Packed { a: i8, b: i64, } -//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]' +//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.packed" 4 +//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.kind" '"rust"' #[repr(packed(4))] pub struct PackedAligned { a: i8, diff --git a/tests/rustdoc-json/attrs/target_feature.rs b/tests/rustdoc-json/attrs/target_feature.rs index 01bc4f54d322..efe3752c1660 100644 --- a/tests/rustdoc-json/attrs/target_feature.rs +++ b/tests/rustdoc-json/attrs/target_feature.rs @@ -1,38 +1,49 @@ -//@ is "$.index[?(@.name=='test1')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='test1')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test1')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test1')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub fn test1() {} -//@ is "$.index[?(@.name=='test2')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]' //@ is "$.index[?(@.name=='test2')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test2')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test2')].attrs[*].target_feature.enable" '["avx", "avx2"]' #[target_feature(enable = "avx,avx2")] pub fn test2() {} -//@ is "$.index[?(@.name=='test3')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]' //@ is "$.index[?(@.name=='test3')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test3')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test3')].attrs[*].target_feature.enable" '["avx", "avx2"]' #[target_feature(enable = "avx", enable = "avx2")] pub fn test3() {} -//@ is "$.index[?(@.name=='test4')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\", enable=\"avx512f\")]"]' //@ is "$.index[?(@.name=='test4')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test4')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test4')].attrs[*].target_feature.enable" '["avx", "avx2", "avx512f"]' #[target_feature(enable = "avx", enable = "avx2,avx512f")] pub fn test4() {} -//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' +//@ count "$.index[?(@.name=='test5')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test5')].attrs[*].target_feature.enable" '["avx", "avx2"]' +#[target_feature(enable = "avx")] +#[target_feature(enable = "avx2")] +pub fn test5() {} + //@ is "$.index[?(@.name=='test_unsafe_fn')].inner.function.header.is_unsafe" true +//@ count "$.index[?(@.name=='test_unsafe_fn')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub unsafe fn test_unsafe_fn() {} pub struct Example; impl Example { - //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='safe_assoc_fn')].inner.function.header.is_unsafe" false + //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub fn safe_assoc_fn() {} - //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='unsafe_assoc_fn')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub unsafe fn unsafe_assoc_fn() {} } diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index ea669e6a0b30..fed0e545798a 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,5 +1,5 @@ #[repr(i32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"i32"' pub enum Foo { //@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index 1b8e791eb230..54bba76a0634 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,5 +1,5 @@ #[repr(u32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u32"' pub enum Foo { //@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index fea546c9fb60..3198fc2529ef 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -5,7 +5,7 @@ //@ !has "$.index[?(@.name=='match')]" //@ has "$.index[?(@.name=='foo')]" -//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' +//@ is "$.index[?(@.name=='foo')].attrs[*].other" '"#[doc(keyword = \"match\")]"' //@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! @@ -13,7 +13,7 @@ pub mod foo {} //@ !has "$.index[?(@.name=='break')]" //@ has "$.index[?(@.name=='bar')]" -//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]' +//@ is "$.index[?(@.name=='bar')].attrs[*].other" '"#[doc(keyword = \"break\")]"' //@ is "$.index[?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "break")] /// hello diff --git a/tests/rustdoc-json/visibility/doc_hidden_documented.rs b/tests/rustdoc-json/visibility/doc_hidden_documented.rs index 6e9ef48680be..f05e4f9d92d5 100644 --- a/tests/rustdoc-json/visibility/doc_hidden_documented.rs +++ b/tests/rustdoc-json/visibility/doc_hidden_documented.rs @@ -1,15 +1,15 @@ //@ compile-flags: --document-hidden-items #![no_std] -//@ is "$.index[?(@.name=='func')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='func')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub fn func() {} -//@ is "$.index[?(@.name=='Unit')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='Unit')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub struct Unit; -//@ is "$.index[?(@.name=='hidden')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='hidden')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub mod hidden { //@ is "$.index[?(@.name=='Inner')].attrs" '[]' diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index aa52de63a609..5026687b97b0 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -100,7 +100,7 @@ //~^ ERROR malformed //~| ERROR the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type #[cfg] -//~^ ERROR is not followed by parentheses +//~^ ERROR malformed #[cfg_attr] //~^ ERROR malformed #[instruction_set] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 3dc3c32c936b..56f2be353e76 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,8 +1,11 @@ -error: `cfg` is not followed by parentheses +error[E0539]: malformed `cfg` attribute input --> $DIR/malformed-attrs.rs:102:1 | LL | #[cfg] - | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg(predicate)]` error: malformed `cfg_attr` attribute input --> $DIR/malformed-attrs.rs:104:1 diff --git a/tests/ui/cfg/cfg-target-compact-errors.rs b/tests/ui/cfg/cfg-target-compact-errors.rs index e00d42fe4d96..cfb19c58a197 100644 --- a/tests/ui/cfg/cfg-target-compact-errors.rs +++ b/tests/ui/cfg/cfg-target-compact-errors.rs @@ -3,19 +3,23 @@ #![feature(cfg_target_compact)] #[cfg(target(o::o))] -//~^ ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input fn one() {} #[cfg(target(os = 8))] -//~^ ERROR literal in `cfg` predicate value must be a string +//~^ ERROR malformed `cfg` attribute input fn two() {} #[cfg(target(os = "linux", pointer(width = "64")))] -//~^ ERROR invalid predicate `target_pointer` +//~^ ERROR malformed `cfg` attribute input fn three() {} #[cfg(target(true))] -//~^ ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input fn four() {} +#[cfg(target(clippy::os = "linux"))] +//~^ ERROR `cfg` predicate key must be an identifier +fn five() {} + fn main() {} diff --git a/tests/ui/cfg/cfg-target-compact-errors.stderr b/tests/ui/cfg/cfg-target-compact-errors.stderr index 219d9732c32b..7df6729e8812 100644 --- a/tests/ui/cfg/cfg-target-compact-errors.stderr +++ b/tests/ui/cfg/cfg-target-compact-errors.stderr @@ -1,28 +1,45 @@ -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-target-compact-errors.rs:5:14 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:5:1 | LL | #[cfg(target(o::o))] - | ^^^^ + | ^^^^^^^^^^^^^----^^^ + | | | + | | expected this to be of the form `... = "..."` + | help: must be of the form: `#[cfg(predicate)]` -error[E0565]: literal in `cfg` predicate value must be a string - --> $DIR/cfg-target-compact-errors.rs:9:19 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:9:1 | LL | #[cfg(target(os = 8))] - | ^ + | ^^^^^^^^^^^^^^^^^^-^^^ + | | | + | | expected a string literal here + | help: must be of the form: `#[cfg(predicate)]` -error[E0537]: invalid predicate `target_pointer` - --> $DIR/cfg-target-compact-errors.rs:13:28 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:13:1 | LL | #[cfg(target(os = "linux", pointer(width = "64")))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------^^^ + | | | + | | expected this to be of the form `... = "..."` + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-target-compact-errors.rs:17:14 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:17:1 | LL | #[cfg(target(true))] - | ^^^^ + | ^^^^^^^^^^^^^----^^^ + | | | + | | expected this to be of the form `... = "..."` + | help: must be of the form: `#[cfg(predicate)]` -error: aborting due to 4 previous errors +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-target-compact-errors.rs:21:14 + | +LL | #[cfg(target(clippy::os = "linux"))] + | ^^^^^^^^^^ -Some errors have detailed explanations: E0537, E0565. -For more information about an error, try `rustc --explain E0537`. +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/cfg/cfg-version/syntax.stderr b/tests/ui/cfg/cfg-version/syntax.stderr index 2facd9607631..188f6d7aa5dc 100644 --- a/tests/ui/cfg/cfg-version/syntax.stderr +++ b/tests/ui/cfg/cfg-version/syntax.stderr @@ -17,10 +17,10 @@ LL | #[cfg(version(false))] | ^^^^^ error: expected single version literal - --> $DIR/syntax.rs:23:7 + --> $DIR/syntax.rs:23:14 | LL | #[cfg(version("1.43", "1.44", "1.45"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unknown version literal format, assuming it refers to a future version --> $DIR/syntax.rs:51:15 diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr index 3e32a856e954..155b3db2f429 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.stderr +++ b/tests/ui/cfg/diagnostics-cross-crate.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/auxiliary/cfged_out.rs:5:5 + --> $DIR/auxiliary/cfged_out.rs:5:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `uwu` in crate `cfged_out` --> $DIR/diagnostics-cross-crate.rs:7:16 @@ -33,10 +33,10 @@ note: found an item that was configured out LL | pub fn uwu() {} | ^^^ note: the item is gated here - --> $DIR/auxiliary/cfged_out.rs:2:5 + --> $DIR/auxiliary/cfged_out.rs:2:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `meow` in module `cfged_out::inner::right` --> $DIR/diagnostics-cross-crate.rs:24:30 @@ -67,10 +67,10 @@ note: found an item that was configured out LL | pub fn vanished() {} | ^^^^^^^^ note: the item is gated here - --> $DIR/auxiliary/cfged_out.rs:21:1 + --> $DIR/auxiliary/cfged_out.rs:21:7 | LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/cfg/diagnostics-reexport-2.stderr b/tests/ui/cfg/diagnostics-reexport-2.stderr index 95ac5a19b0b9..e1f91fcc5d10 100644 --- a/tests/ui/cfg/diagnostics-reexport-2.stderr +++ b/tests/ui/cfg/diagnostics-reexport-2.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport2` --> $DIR/diagnostics-reexport-2.rs:46:16 @@ -27,10 +27,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport30` --> $DIR/diagnostics-reexport-2.rs:50:17 @@ -44,10 +44,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport31` --> $DIR/diagnostics-reexport-2.rs:54:17 @@ -61,10 +61,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport32` --> $DIR/diagnostics-reexport-2.rs:58:17 @@ -78,10 +78,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr index 95dc4fac945e..bf1bbcba7e4c 100644 --- a/tests/ui/cfg/diagnostics-reexport.stderr +++ b/tests/ui/cfg/diagnostics-reexport.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub fn x() {} | ^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:17:5 + --> $DIR/diagnostics-reexport.rs:17:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0432]: unresolved imports `b::x`, `b::y` --> $DIR/diagnostics-reexport.rs:22:13 @@ -29,20 +29,20 @@ note: found an item that was configured out LL | pub fn x() {} | ^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:28:5 + --> $DIR/diagnostics-reexport.rs:28:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ note: found an item that was configured out --> $DIR/diagnostics-reexport.rs:32:12 | LL | pub fn y() {} | ^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:31:5 + --> $DIR/diagnostics-reexport.rs:31:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `uwu` in module `inner` --> $DIR/diagnostics-reexport.rs:38:12 @@ -56,10 +56,10 @@ note: found an item that was configured out LL | pub use super::uwu; | ^^^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:7:5 + --> $DIR/diagnostics-reexport.rs:7:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index 75a1bc39a013..121f25ca0906 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:8:5 + --> $DIR/diagnostics-same-crate.rs:8:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0432]: unresolved import `super::inner::doesnt_exist` --> $DIR/diagnostics-same-crate.rs:35:23 @@ -27,10 +27,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:8:5 + --> $DIR/diagnostics-same-crate.rs:8:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` --> $DIR/diagnostics-same-crate.rs:54:12 @@ -44,10 +44,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:8:5 + --> $DIR/diagnostics-same-crate.rs:8:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `uwu` in module `inner` --> $DIR/diagnostics-same-crate.rs:49:12 @@ -61,10 +61,10 @@ note: found an item that was configured out LL | pub fn uwu() {} | ^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:4:5 + --> $DIR/diagnostics-same-crate.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `meow` in module `inner::right` --> $DIR/diagnostics-same-crate.rs:58:19 diff --git a/tests/ui/check-cfg/compact-names.rs b/tests/ui/check-cfg/compact-names.rs index 931afdf986f4..fbf8f9d20028 100644 --- a/tests/ui/check-cfg/compact-names.rs +++ b/tests/ui/check-cfg/compact-names.rs @@ -13,4 +13,8 @@ pub fn expected() {} //~^ WARNING unexpected `cfg` condition name pub fn unexpected() {} +#[cfg(target(os = "windows", architecture = "arm"))] +//~^ WARNING unexpected `cfg` condition name +pub fn unexpected2() {} + fn main() {} diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index 74ed0337e3b1..3221b4e07ec9 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -8,5 +8,14 @@ LL | #[cfg(target(os = "linux", architecture = "arm"))] = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default -warning: 1 warning emitted +warning: unexpected `cfg` condition name: `target_architecture` + --> $DIR/compact-names.rs:16:30 + | +LL | #[cfg(target(os = "windows", architecture = "arm"))] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))` + = note: see for more information about checking conditional configuration + +warning: 2 warnings emitted diff --git a/tests/ui/codegen/duplicated-path-in-error.stderr b/tests/ui/codegen/duplicated-path-in-error.gnu.stderr similarity index 100% rename from tests/ui/codegen/duplicated-path-in-error.stderr rename to tests/ui/codegen/duplicated-path-in-error.gnu.stderr diff --git a/tests/ui/codegen/duplicated-path-in-error.musl.stderr b/tests/ui/codegen/duplicated-path-in-error.musl.stderr new file mode 100644 index 000000000000..2892ebffdde6 --- /dev/null +++ b/tests/ui/codegen/duplicated-path-in-error.musl.stderr @@ -0,0 +1,2 @@ +error: couldn't load codegen backend /non-existing-one.so: Error loading shared library /non-existing-one.so: No such file or directory + diff --git a/tests/ui/codegen/duplicated-path-in-error.rs b/tests/ui/codegen/duplicated-path-in-error.rs index a446395de208..fed93828ee2a 100644 --- a/tests/ui/codegen/duplicated-path-in-error.rs +++ b/tests/ui/codegen/duplicated-path-in-error.rs @@ -1,8 +1,15 @@ +//@ revisions: musl gnu //@ only-linux +//@ ignore-cross-compile because this relies on host libc behaviour //@ compile-flags: -Zcodegen-backend=/non-existing-one.so +//@[gnu] only-gnu +//@[musl] only-musl // This test ensures that the error of the "not found dylib" doesn't duplicate // the path of the dylib. +// +// glibc and musl have different dlopen error messages, so the expected error +// message differs between the two. fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 47418b4e091b..df87a3d846ef 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -1,16 +1,24 @@ -#[cfg] //~ ERROR `cfg` is not followed by parentheses +#[cfg] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected this to be a list struct S1; -#[cfg = 10] //~ ERROR `cfg` is not followed by parentheses +#[cfg = 10] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected this to be a list struct S2; -#[cfg()] //~ ERROR `cfg` predicate is not specified +#[cfg()] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected a single argument here struct S3; -#[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified +#[cfg(a, b)] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected a single argument here struct S4; -#[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal +#[cfg("str")] //~ ERROR `cfg` predicate key must be an identifier struct S5; #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier @@ -19,10 +27,12 @@ struct S6; #[cfg(a())] //~ ERROR invalid predicate `a` struct S7; -#[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string +#[cfg(a = 10)] //~ ERROR malformed `cfg` attribute input +//~^ NOTE expected a string literal here struct S8; -#[cfg(a = b"hi")] //~ ERROR literal in `cfg` predicate value must be a string +#[cfg(a = b"hi")] //~ ERROR malformed `cfg` attribute input +//~^ NOTE expected a normal string literal, not a byte string literal struct S9; macro_rules! generate_s10 { @@ -34,5 +44,6 @@ macro_rules! generate_s10 { } generate_s10!(concat!("nonexistent")); +//~^ NOTE in this expansion of generate_s10! fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 66ce2ee98589..75e9b9209c08 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -1,61 +1,78 @@ -error: `cfg` is not followed by parentheses +error[E0539]: malformed `cfg` attribute input --> $DIR/cfg-attr-syntax-validation.rs:1:1 | LL | #[cfg] - | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` is not followed by parentheses - --> $DIR/cfg-attr-syntax-validation.rs:4:1 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:6:1 | LL | #[cfg = 10] - | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` predicate is not specified - --> $DIR/cfg-attr-syntax-validation.rs:7:1 +error[E0805]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:11:1 | LL | #[cfg()] - | ^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^--^ + | | | + | | expected a single argument here + | help: must be of the form: `#[cfg(predicate)]` -error: multiple `cfg` predicates are specified - --> $DIR/cfg-attr-syntax-validation.rs:10:10 +error[E0805]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:16:1 | LL | #[cfg(a, b)] - | ^ + | ^^^^^------^ + | | | + | | expected a single argument here + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` predicate key cannot be a literal - --> $DIR/cfg-attr-syntax-validation.rs:13:7 +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-attr-syntax-validation.rs:21:7 | LL | #[cfg("str")] | ^^^^^ error: `cfg` predicate key must be an identifier - --> $DIR/cfg-attr-syntax-validation.rs:16:7 + --> $DIR/cfg-attr-syntax-validation.rs:24:7 | LL | #[cfg(a::b)] | ^^^^ error[E0537]: invalid predicate `a` - --> $DIR/cfg-attr-syntax-validation.rs:19:7 + --> $DIR/cfg-attr-syntax-validation.rs:27:7 | LL | #[cfg(a())] | ^^^ -error[E0565]: literal in `cfg` predicate value must be a string - --> $DIR/cfg-attr-syntax-validation.rs:22:11 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:30:1 | LL | #[cfg(a = 10)] - | ^^ + | ^^^^^^^^^^--^^ + | | | + | | expected a string literal here + | help: must be of the form: `#[cfg(predicate)]` -error[E0565]: literal in `cfg` predicate value must be a string - --> $DIR/cfg-attr-syntax-validation.rs:25:11 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:34:1 | LL | #[cfg(a = b"hi")] - | -^^^^ + | ^^^^^^^^^^-^^^^^^ | | | help: consider removing the prefix + | + = note: expected a normal string literal, not a byte string literal error: expected unsuffixed literal, found `expr` metavariable - --> $DIR/cfg-attr-syntax-validation.rs:30:25 + --> $DIR/cfg-attr-syntax-validation.rs:40:25 | LL | #[cfg(feature = $expr)] | ^^^^^ @@ -67,5 +84,5 @@ LL | generate_s10!(concat!("nonexistent")); error: aborting due to 10 previous errors -Some errors have detailed explanations: E0537, E0565. +Some errors have detailed explanations: E0537, E0539, E0805. For more information about an error, try `rustc --explain E0537`. diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs index e805ac01c9d0..ad2b49e60498 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs @@ -1,9 +1,10 @@ -//@ known-bug: #110395 +#![feature(const_index, const_trait_impl)] const A: [(); 5] = [(), (), (), (), ()]; // Since the indexing is on a ZST, the addresses are all fine, // but we should still catch the bad range. const B: &[()] = unsafe { A.get_unchecked(3..1) }; +//~^ ERROR: slice::get_unchecked requires that the range is within the slice fn main() {} diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr index 6e428079afe8..88ea310f19c6 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr @@ -1,11 +1,11 @@ -error[E0015]: cannot call non-const method `core::slice::::get_unchecked::>` in constants - --> $DIR/ub-slice-get-unchecked.rs:7:29 +error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the range is within the slice + + This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. + --> $DIR/ub-slice-get-unchecked.rs:7:27 | LL | const B: &[()] = unsafe { A.get_unchecked(3..1) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `B` failed here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs index ed5ff769701f..f1bb8cddf774 100644 --- a/tests/ui/consts/const_transmute_type_id3.rs +++ b/tests/ui/consts/const_transmute_type_id3.rs @@ -1,3 +1,6 @@ +//! Test that all bytes of a TypeId must have the +//! TypeId marker provenance. + #![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; @@ -10,7 +13,7 @@ const _: () = { std::ptr::write(ptr.offset(1), 999); } assert!(a == b); - //~^ ERROR: one of the TypeId arguments is invalid, the hash does not match the type it represents + //~^ ERROR: pointer must point to some allocation }; fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr index 8cfdcfebaa4c..e731f496652e 100644 --- a/tests/ui/consts/const_transmute_type_id3.stderr +++ b/tests/ui/consts/const_transmute_type_id3.stderr @@ -1,5 +1,5 @@ -error[E0080]: type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents - --> $DIR/const_transmute_type_id3.rs:12:13 +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x3e7[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/const_transmute_type_id3.rs:15:13 | LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs new file mode 100644 index 000000000000..0a9ba01e0dd7 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id5.rs @@ -0,0 +1,21 @@ +//! Test that we require an equal TypeId to have the same integer +//! part, even if the provenance matches. + +#![feature(const_type_id, const_trait_impl, const_cmp)] + +use std::any::TypeId; + +const _: () = { + let a = TypeId::of::<()>(); + let mut b = TypeId::of::<()>(); + unsafe { + let ptr = &mut b as *mut TypeId as *mut *const (); + // Copy the ptr at index 0 to index 1 + let val = std::ptr::read(ptr); + std::ptr::write(ptr.offset(1), val); + } + assert!(a == b); + //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr new file mode 100644 index 000000000000..59823fcc1c9f --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id5.stderr @@ -0,0 +1,15 @@ +error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents + --> $DIR/const_transmute_type_id5.rs:17:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 87c8b04452ba..22791e7d15e5 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -7,7 +7,9 @@ struct Foo<'a> { impl<'a> Foo<'a> { const fn spam(&mut self, baz: &mut Vec) { self.bar[0] = baz.len(); - //~^ ERROR: cannot call + //~^ ERROR: `Vec: [const] Index<_>` is not satisfied + //~| ERROR: `Vec: [const] Index` is not satisfied + //~| ERROR: `Vec: [const] IndexMut` is not satisfied } } diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index 63a86b456332..608ce0cfef01 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,13 +1,24 @@ -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-94675.rs:9:17 +error[E0277]: the trait bound `Vec: [const] Index<_>` is not satisfied + --> $DIR/issue-94675.rs:9:9 | LL | self.bar[0] = baz.len(); - | ^^^ + | ^^^^^^^^^^^ + +error[E0277]: the trait bound `Vec: [const] IndexMut` is not satisfied + --> $DIR/issue-94675.rs:9:9 | -note: impl defined here, but it is not `const` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `Vec: [const] Index` is not satisfied + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ + | +note: required by a bound in `std::ops::IndexMut::index_mut` + --> $SRC_DIR/core/src/ops/index.rs:LL:COL -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index 8c52586c485f..98a50156a948 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -5,17 +5,17 @@ use std::ptr; //@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes" -pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR -pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR -pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR +pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR: is at the beginning of the allocation +pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR: only 1 byte from the end of the allocation +pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR: only 100 bytes from the end of the allocation -pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR -pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR +pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR: does not fit in an `isize` +pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR: does not fit in an `isize` pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~ ERROR pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~ ERROR -pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR +pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR: before the beginning of the allocation -pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR +pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR: at or beyond the end of the allocation pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; //~ ERROR // Make sure that we don't panic when computing abs(offset*size_of::()) diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 255583ce91c5..d92ca09223de 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -40,11 +40,11 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ADDRESS_SPACE` failed here -error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which points to before the beginning of the allocation --> $DIR/offset_ub.rs:16:49 | -LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here +LL | ...*const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes --> $DIR/offset_ub.rs:18:50 diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed deleted file mode 100644 index 6d73f17cca4c..000000000000 --- a/tests/ui/issues/issue-50571.fixed +++ /dev/null @@ -1,10 +0,0 @@ -//@ edition: 2015 -//@ run-rustfix - -#![allow(dead_code)] -trait Foo { - fn foo(_: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies -} - -fn main() {} diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs deleted file mode 100644 index dd840ffe4d17..000000000000 --- a/tests/ui/issues/issue-50571.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ edition: 2015 -//@ run-rustfix - -#![allow(dead_code)] -trait Foo { - fn foo([a, b]: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies -} - -fn main() {} diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr deleted file mode 100644 index 9b00fe0f5db6..000000000000 --- a/tests/ui/issues/issue-50571.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/issue-50571.rs:6:12 - | -LL | fn foo([a, b]: [i32; 2]) {} - | ^^^^^^ - | -help: give this argument a name or use an underscore to ignore it - | -LL - fn foo([a, b]: [i32; 2]) {} -LL + fn foo(_: [i32; 2]) {} - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index a4d94836a09a..461d2e0e8c1f 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -18,10 +18,13 @@ fn arm_rhs_must_be_in_braces() -> i32 { cfg_select! { _ => {} true => {} - //~^ WARN unreachable rule + //~^ WARN unreachable predicate } cfg_select! { - //~^ ERROR none of the rules in this `cfg_select` evaluated to true + //~^ ERROR none of the predicates in this `cfg_select` evaluated to true false => {} } + +cfg_select! {} +//~^ ERROR none of the predicates in this `cfg_select` evaluated to true diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index fef5e95a6bce..6c18a7c189dc 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -4,15 +4,15 @@ error: expected `{`, found `1` LL | true => 1 | ^ expected `{` -warning: unreachable rule +warning: unreachable predicate --> $DIR/cfg_select.rs:20:5 | LL | _ => {} | - always matches LL | true => {} - | ^^^^ this rules is never reached + | ^^^^ this predicate is never reached -error: none of the rules in this `cfg_select` evaluated to true +error: none of the predicates in this `cfg_select` evaluated to true --> $DIR/cfg_select.rs:24:1 | LL | / cfg_select! { @@ -21,5 +21,11 @@ LL | | false => {} LL | | } | |_^ -error: aborting due to 2 previous errors; 1 warning emitted +error: none of the predicates in this `cfg_select` evaluated to true + --> $DIR/cfg_select.rs:29:1 + | +LL | cfg_select! {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index a894c90f4c32..9215754d4bb1 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -10,16 +10,10 @@ note: found an item that was configured out LL | pub fn bar() { }); | ^^^ note: the item is gated here - --> $DIR/macro-outer-attributes.rs:5:45 + --> $DIR/macro-outer-attributes.rs:8:13 | -LL | $i:item) => (mod $nm { #[$a] $i }); } - | ^^^^^ -LL | -LL | / test!(a, -LL | | #[cfg(false)], -LL | | pub fn bar() { }); - | |_______________________- in this macro invocation - = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | #[cfg(false)], + | ^^^^^ help: consider importing this function | LL + use b::bar; diff --git a/tests/ui/parser/better-expected.rs b/tests/ui/parser/better-expected.rs index 16b61caa4dff..91128c39691d 100644 --- a/tests/ui/parser/better-expected.rs +++ b/tests/ui/parser/better-expected.rs @@ -1,3 +1,3 @@ fn main() { - let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` + let x: [isize 3]; //~ ERROR expected `;` or `]`, found `3` } diff --git a/tests/ui/parser/better-expected.stderr b/tests/ui/parser/better-expected.stderr index f4ec933be164..4646ce7eff0e 100644 --- a/tests/ui/parser/better-expected.stderr +++ b/tests/ui/parser/better-expected.stderr @@ -1,10 +1,14 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` +error: expected `;` or `]`, found `3` --> $DIR/better-expected.rs:2:19 | LL | let x: [isize 3]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `x` + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL | let x: [isize ;3]; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.rs b/tests/ui/parser/issues/error-pattern-issue-50571.rs new file mode 100644 index 000000000000..0c2ce6052cb8 --- /dev/null +++ b/tests/ui/parser/issues/error-pattern-issue-50571.rs @@ -0,0 +1,11 @@ +// There is a regression introduced for issue #143828 +//@ edition: 2015 + +#![allow(dead_code)] +trait Foo { + fn foo([a, b]: [i32; 2]) {} + //~^ ERROR: expected `;` or `]`, found `,` + //~| ERROR: patterns aren't allowed in methods without bodies +} + +fn main() {} diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.stderr b/tests/ui/parser/issues/error-pattern-issue-50571.stderr new file mode 100644 index 000000000000..47457cff461c --- /dev/null +++ b/tests/ui/parser/issues/error-pattern-issue-50571.stderr @@ -0,0 +1,28 @@ +error: expected `;` or `]`, found `,` + --> $DIR/error-pattern-issue-50571.rs:6:14 + | +LL | fn foo([a, b]: [i32; 2]) {} + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - fn foo([a, b]: [i32; 2]) {} +LL + fn foo([a; b]: [i32; 2]) {} + | + +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/error-pattern-issue-50571.rs:6:12 + | +LL | fn foo([a, b]: [i32; 2]) {} + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - fn foo([a, b]: [i32; 2]) {} +LL + fn foo(_: [i32; 2]) {} + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs index 316c612940c9..439793ea8f72 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs @@ -1,6 +1,6 @@ //@ edition:2018 #![crate_type = "lib"] -#![feature(type_ascription)] +#![feature(type_ascription, const_index, const_trait_impl)] use std::future::Future; use std::pin::Pin; @@ -129,7 +129,6 @@ pub fn inside_block() { static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); //~^ ERROR: cast cannot be followed by indexing -//~| ERROR: cannot call non-const operator in statics static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); //~^ ERROR: expected one of diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr index 64cf8baf9a5d..ce7129da9371 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -219,13 +219,13 @@ LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]); | + + error: expected one of `)`, `,`, `.`, `?`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:134:36 + --> $DIR/issue-35813-postfix-after-cast.rs:133:36 | LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); | ^ expected one of `)`, `,`, `.`, `?`, or an operator error: cast cannot be followed by `?` - --> $DIR/issue-35813-postfix-after-cast.rs:139:5 + --> $DIR/issue-35813-postfix-after-cast.rs:138:5 | LL | Err(0u64) as Result?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,25 +236,25 @@ LL | (Err(0u64) as Result)?; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:141:14 + --> $DIR/issue-35813-postfix-after-cast.rs:140:14 | LL | Err(0u64): Result?; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: expected identifier, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:153:13 + --> $DIR/issue-35813-postfix-after-cast.rs:152:13 | LL | drop_ptr: F(); | ^ expected identifier error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:160:13 + --> $DIR/issue-35813-postfix-after-cast.rs:159:13 | LL | drop_ptr: fn(u8); | ^ expected one of 8 possible tokens error: cast cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:166:5 + --> $DIR/issue-35813-postfix-after-cast.rs:165:5 | LL | drop as fn(u8)(0); | ^^^^^^^^^^^^^^ @@ -265,13 +265,13 @@ LL | (drop as fn(u8))(0); | + + error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:168:13 + --> $DIR/issue-35813-postfix-after-cast.rs:167:13 | LL | drop_ptr: fn(u8)(0); | ^ expected one of 8 possible tokens error: cast cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:173:5 + --> $DIR/issue-35813-postfix-after-cast.rs:172:5 | LL | Box::pin(noop()) as Pin>>.await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -282,13 +282,13 @@ LL | (Box::pin(noop()) as Pin>>).await; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:176:21 + --> $DIR/issue-35813-postfix-after-cast.rs:175:21 | LL | Box::pin(noop()): Pin>.await; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: cast cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:188:5 + --> $DIR/issue-35813-postfix-after-cast.rs:187:5 | LL | Foo::default() as Foo.bar; | ^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ LL | (Foo::default() as Foo).bar; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:190:19 + --> $DIR/issue-35813-postfix-after-cast.rs:189:19 | LL | Foo::default(): Foo.bar; | ^ expected one of `.`, `;`, `?`, `}`, or an operator @@ -322,21 +322,11 @@ LL | if true { 33 } else { 44 }: i32.max(0) | ^ expected one of `,`, `.`, `?`, or an operator error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:151:13 + --> $DIR/issue-35813-postfix-after-cast.rs:150:13 | LL | drop as F(); | ^^^ only `Fn` traits may use parentheses -error[E0015]: cannot call non-const operator in statics - --> $DIR/issue-35813-postfix-after-cast.rs:130:42 - | -LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); - | ^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` +error: aborting due to 39 previous errors -error: aborting due to 40 previous errors - -Some errors have detailed explanations: E0015, E0214. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0214`. diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs new file mode 100644 index 000000000000..2cc5d979604c --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi.rs @@ -0,0 +1,17 @@ +// when the next token is not a semicolon, +// we should suggest to use semicolon if recovery is allowed +// See issue #143828 + +fn main() { + let x = 5; + let b: [i32, 5]; + //~^ ERROR expected `;` or `]`, found `,` + let a: [i32, ]; + //~^ ERROR expected `;` or `]`, found `,` + //~| ERROR expected value, found builtin type `i32` [E0423] + let c: [i32, x]; + //~^ ERROR expected `;` or `]`, found `,` + //~| ERROR attempt to use a non-constant value in a constant [E0435] + let e: [i32 5]; + //~^ ERROR expected `;` or `]`, found `5` +} diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr new file mode 100644 index 000000000000..82330465144c --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -0,0 +1,71 @@ +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi.rs:7:16 + | +LL | let b: [i32, 5]; + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - let b: [i32, 5]; +LL + let b: [i32; 5]; + | + +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi.rs:9:16 + | +LL | let a: [i32, ]; + | - ^ expected `;` or `]` + | | + | while parsing the type for `a` + | help: use `=` if you meant to assign + | + = note: you might have meant to write a slice or array type + +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi.rs:12:16 + | +LL | let c: [i32, x]; + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - let c: [i32, x]; +LL + let c: [i32; x]; + | + +error: expected `;` or `]`, found `5` + --> $DIR/array-type-no-semi.rs:15:17 + | +LL | let e: [i32 5]; + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL | let e: [i32 ;5]; + | + + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/array-type-no-semi.rs:12:18 + | +LL | let c: [i32, x]; + | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL - let x = 5; +LL + const x: /* Type */ = 5; + | + +error[E0423]: expected value, found builtin type `i32` + --> $DIR/array-type-no-semi.rs:9:13 + | +LL | let a: [i32, ]; + | ^^^ not a value + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0423, E0435. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs index 560efecb91cf..fb9a1c643fcc 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs @@ -1 +1,6 @@ -type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` +type v = [isize * 3]; +//~^ ERROR expected `;` or `]`, found `*` +//~| WARN type `v` should have an upper camel case name [non_camel_case_types] + + +fn main() {} diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr index 5bc9c2ccf00a..8d7938a1a469 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr @@ -1,8 +1,23 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` +error: expected `;` or `]`, found `*` --> $DIR/removed-syntax-fixed-vec.rs:1:17 | LL | type v = [isize * 3]; - | ^ expected one of 7 possible tokens + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - type v = [isize * 3]; +LL + type v = [isize ; 3]; + | -error: aborting due to 1 previous error +warning: type `v` should have an upper camel case name + --> $DIR/removed-syntax-fixed-vec.rs:1:6 + | +LL | type v = [isize * 3]; + | ^ help: convert the identifier to upper camel case (notice the capitalization): `V` + | + = note: `#[warn(non_camel_case_types)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/precondition-checks/vec-from-parts.rs b/tests/ui/precondition-checks/vec-from-parts.rs new file mode 100644 index 000000000000..0bafb5aa715e --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-parts.rs @@ -0,0 +1,15 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity +#![feature(allocator_api)] + +use std::ptr::NonNull; + +fn main() { + let ptr: NonNull = std::ptr::NonNull::dangling(); + // Test Vec::from_parts_in with length > capacity + unsafe { + let alloc = std::alloc::Global; + let _vec = Vec::from_parts_in(ptr, 10, 5, alloc); + } +} diff --git a/tests/ui/precondition-checks/vec-from-raw-parts.rs b/tests/ui/precondition-checks/vec-from-raw-parts.rs new file mode 100644 index 000000000000..884d34c0a564 --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-raw-parts.rs @@ -0,0 +1,29 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity +//@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts + +#![feature(allocator_api)] + +fn main() { + let ptr = std::ptr::null_mut::(); + // Test Vec::from_raw_parts with length > capacity + unsafe { + #[cfg(vec_from_raw_parts)] + let _vec = Vec::from_raw_parts(ptr, 10, 5); + } + + // Test Vec::from_raw_parts_in with length > capacity + unsafe { + let alloc = std::alloc::Global; + #[cfg(vec_from_raw_parts_in)] + let _vec = Vec::from_raw_parts_in(ptr, 10, 5, alloc); + } + + // Test String::from_raw_parts with length > capacity + // Because it calls Vec::from_raw_parts, it should also fail + unsafe { + #[cfg(string_from_raw_parts)] + let _vec = String::from_raw_parts(ptr, 10, 5); + } +} diff --git a/tests/ui/precondition-checks/vec-set-len.rs b/tests/ui/precondition-checks/vec-set-len.rs new file mode 100644 index 000000000000..0987e7fe0282 --- /dev/null +++ b/tests/ui/precondition-checks/vec-set-len.rs @@ -0,0 +1,11 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity() + +fn main() { + let mut vec: Vec = Vec::with_capacity(5); + // Test set_len with length > capacity + unsafe { + vec.set_len(10); + } +} diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 1734b9afe92e..91d16eca1b0a 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -49,12 +49,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 42257312a872..63741326e341 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -72,12 +72,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) diff --git a/tests/ui/span/E0536.rs b/tests/ui/span/E0536.rs index 72de7b6f4530..ae0733633541 100644 --- a/tests/ui/span/E0536.rs +++ b/tests/ui/span/E0536.rs @@ -1,4 +1,3 @@ -#[cfg(not())] //~ ERROR E0536 -pub fn something() {} - -pub fn main() {} +pub fn main() { + if cfg!(not()) { } //~ ERROR E0536 +} diff --git a/tests/ui/span/E0536.stderr b/tests/ui/span/E0536.stderr index b0f652208c4a..6c25f9140a1a 100644 --- a/tests/ui/span/E0536.stderr +++ b/tests/ui/span/E0536.stderr @@ -1,8 +1,8 @@ error[E0536]: expected 1 cfg-pattern - --> $DIR/E0536.rs:1:7 + --> $DIR/E0536.rs:2:13 | -LL | #[cfg(not())] - | ^^^^^ +LL | if cfg!(not()) { } + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs index ece87529c3e3..1d1da9b0e3df 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs @@ -14,5 +14,7 @@ fn main() { trait NonConst {} const fn handle(_: &dyn const NonConst) {} //~^ ERROR const trait bounds are not allowed in trait object types +//~| ERROR `const` can only be applied to `#[const_trait]` traits const fn take(_: &dyn [const] NonConst) {} //~^ ERROR `[const]` is not allowed here +//~| ERROR `[const]` can only be applied to `#[const_trait]` traits diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr index 090555c63779..06e0493024c1 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr @@ -19,12 +19,34 @@ LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:17:23 + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ | = note: trait objects cannot have `[const]` trait bounds -error: aborting due to 4 previous errors +error: `const` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:15:25 + | +LL | const fn handle(_: &dyn const NonConst) {} + | ^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: `[const]` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 + | +LL | const fn take(_: &dyn [const] NonConst) {} + | ^^^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: aborting due to 6 previous errors diff --git a/triagebot.toml b/triagebot.toml index 75e794c700dd..2f8114aeb3b6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -506,7 +506,6 @@ trigger_files = [ "src/tools/remote-test-server", "src/tools/remote-test-client", "src/tools/rustdoc-gui-test", - "src/tools/suggest-tests", ] [autolabel."A-tidy"]