Merge pull request #4473 from rust-lang/rustup-2025-07-17
Automatic Rustup
This commit is contained in:
commit
0131e38aa2
227 changed files with 3054 additions and 3112 deletions
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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<ModId = DefId> {
|
||||
pub parent_module: ModId,
|
||||
pub ident: Ident,
|
||||
pub cfg: MetaItem,
|
||||
}
|
||||
|
||||
impl<ModId> StrippedCfgItem<ModId> {
|
||||
pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
|
||||
StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ModId = DefId> {
|
||||
pub parent_module: ModId,
|
||||
pub ident: Ident,
|
||||
pub cfg: (CfgEntry, Span),
|
||||
}
|
||||
|
||||
impl<ModId> StrippedCfgItem<ModId> {
|
||||
pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
|
||||
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<CfgEntry>, Span),
|
||||
Any(ThinVec<CfgEntry>, Span),
|
||||
Not(Box<CfgEntry>, Span),
|
||||
Bool(bool, Span),
|
||||
NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span },
|
||||
Version(Option<RustcVersion>, 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),
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ impl AttributeKind {
|
|||
ParenSugar(..) => No,
|
||||
PassByValue(..) => Yes,
|
||||
Path(..) => No,
|
||||
Pointee(..) => No,
|
||||
PubTransparent(..) => Yes,
|
||||
Repr { .. } => No,
|
||||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
|
|
|
|||
|
|
@ -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<CfgEntry> {
|
||||
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<Symbol>,
|
||||
pub value_span: Option<Span>,
|
||||
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<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
item: &MetaItemOrLitParser<'_>,
|
||||
) -> Option<CfgEntry> {
|
||||
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<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
list: &MetaItemListParser<'_>,
|
||||
meta_span: Span,
|
||||
) -> Option<CfgEntry> {
|
||||
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<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
list: &MetaItemListParser<'_>,
|
||||
meta_span: Span,
|
||||
) -> Option<CfgEntry> {
|
||||
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<S: Stage>(
|
||||
name: Symbol,
|
||||
name_span: Span,
|
||||
value: Option<&NameValueParser>,
|
||||
span: Span,
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
) -> Option<CfgEntry> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
247
compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
Normal file
247
compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
Normal file
|
|
@ -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<Symbol>,
|
||||
pub value_span: Option<Span>,
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -145,3 +145,10 @@ impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
|
|||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental;
|
||||
}
|
||||
|
||||
pub(crate) struct PointeeParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PointeeParser {
|
||||
const PATH: &[Symbol] = &[sym::pointee];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<WithoutArgs<OmitGdbPrettyPrinterSectionParser>>,
|
||||
Single<WithoutArgs<ParenSugarParser>>,
|
||||
Single<WithoutArgs<PassByValueParser>>,
|
||||
Single<WithoutArgs<PointeeParser>>,
|
||||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||
Single<WithoutArgs<StdInternalSymbolParser>>,
|
||||
|
|
@ -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<Symbol>,
|
||||
features: Option<&'sess Features>,
|
||||
sess: &'sess Session,
|
||||
stage: PhantomData<S>,
|
||||
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<Attribute> {
|
||||
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<T>(
|
||||
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<Symbol>) -> Self {
|
||||
Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
|
||||
pub fn new(
|
||||
sess: &'sess Session,
|
||||
features: &'sess Features,
|
||||
tools: Vec<Symbol>,
|
||||
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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(..)))
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<LlvmCodegenBackend>) ->
|
|||
}
|
||||
|
||||
/// Embed the bitcode of an LLVM module for LTO in the LLVM module itself.
|
||||
unsafe fn embed_bitcode(
|
||||
fn embed_bitcode(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<SCx<'ll>>> 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> {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Self::Metadata> {
|
||||
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<Self::Metadata> {
|
||||
None
|
||||
}
|
||||
fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {}
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
) -> <InterpCx<'tcx, M> 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>) -> <Self as LayoutOfHelpers<'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<Ty<'tcx>>,
|
||||
) -> <Self as FnAbiOfHelpers<'tcx>>::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<Ty<'tcx>>,
|
||||
) -> <Self as FnAbiOfHelpers<'tcx>>::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>(
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<MetaItem>) {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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<ast::MetaItem>) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Id> Res<Id> {
|
|||
}
|
||||
}
|
||||
|
||||
/// If this is a "module" in name resolution sense, return its `DefId`.
|
||||
#[inline]
|
||||
pub fn module_like_def_id(&self) -> Option<DefId> {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ macro_rules! arena_types {
|
|||
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>,
|
||||
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<rustc_middle::ty::TyCtxt<'tcx>>,
|
||||
[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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ trivially_parameterized_over_tcx! {
|
|||
ty::IntrinsicDef,
|
||||
rustc_ast::Attribute,
|
||||
rustc_ast::DelimArgs,
|
||||
rustc_ast::expand::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
|
||||
rustc_attr_data_structures::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
|
||||
rustc_attr_data_structures::ConstStability,
|
||||
rustc_attr_data_structures::DefaultBodyStability,
|
||||
rustc_attr_data_structures::Deprecation,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Ty>) -> 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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<NodeId>;
|
||||
|
||||
impl<'ra, Id: Into<DefId>> ToNameBinding<'ra>
|
||||
for (Module<'ra>, ty::Visibility<Id>, 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<DefId>> ToNameBinding<'ra> for (Res, ty::Visibility<Id>, 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<T>(&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<impl Into<DefId>>,
|
||||
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<ty::Visibility, VisResolutionError<'ast>> {
|
||||
) -> Result<Visibility, VisResolutionError<'ast>> {
|
||||
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::<LocalDefId>::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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<LocalDefId>;
|
||||
|
||||
#[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() {
|
||||
|
|
|
|||
|
|
@ -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<Option<ty::Visibility>>,
|
||||
max_vis: Cell<Option<Visibility>>,
|
||||
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<Option<ModuleOrUniformRoot<'ra>>>,
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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<DefId>),
|
||||
ImplItem(Result<DefId, &'a Visibility>),
|
||||
NestedUse(&'a Visibility),
|
||||
ImplItem(Result<DefId, &'a ast::Visibility>),
|
||||
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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Vec<Import<'ra>>>,
|
||||
|
||||
/// Used to memoize the traits in this module for faster searches through all traits in scope.
|
||||
traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>)]>>>,
|
||||
traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>, Option<Module<'ra>>)]>>>,
|
||||
|
||||
/// 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<DefId>,
|
||||
vis: Visibility<DefId>,
|
||||
}
|
||||
|
||||
/// 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<Module<'ra>> {
|
||||
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<LocalDefId, FxIndexSet<Symbol>>,
|
||||
glob_error: Option<ErrorGuaranteed>,
|
||||
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
|
||||
visibilities_for_hashing: Vec<(LocalDefId, Visibility)>,
|
||||
used_imports: FxHashSet<NodeId>,
|
||||
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
||||
|
||||
|
|
@ -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<DefId>, Vec<ty::Visibility<DefId>>)>,
|
||||
struct_constructors: LocalDefIdMap<(Res, Visibility<DefId>, Vec<Visibility<DefId>>)>,
|
||||
|
||||
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<DefId>,
|
||||
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<Module<'ra>>,
|
||||
|
|
@ -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::<DefId>::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::<DefId>::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<impl Into<DefId>>,
|
||||
module: Module<'ra>,
|
||||
) -> bool {
|
||||
fn is_accessible_from(&self, vis: Visibility<impl Into<DefId>>, 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::<DefId>::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)
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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<NodeId>;
|
||||
|
|
@ -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::<DefId>::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 {
|
||||
|
|
|
|||
|
|
@ -12,12 +12,6 @@ use crate::{self as ty, Interner};
|
|||
// avoid heap allocations.
|
||||
type TypeWalkerStack<I> = SmallVec<[<I as Interner>::GenericArg; 8]>;
|
||||
|
||||
pub struct TypeWalker<I: Interner> {
|
||||
stack: TypeWalkerStack<I>,
|
||||
last_subtree: usize,
|
||||
pub visited: SsoHashSet<I::GenericArg>,
|
||||
}
|
||||
|
||||
/// An iterator for walking the type tree.
|
||||
///
|
||||
/// It's very easy to produce a deeply
|
||||
|
|
@ -26,6 +20,12 @@ pub struct TypeWalker<I: Interner> {
|
|||
/// 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<I: Interner> {
|
||||
stack: TypeWalkerStack<I>,
|
||||
last_subtree: usize,
|
||||
pub visited: SsoHashSet<I::GenericArg>,
|
||||
}
|
||||
|
||||
impl<I: Interner> TypeWalker<I> {
|
||||
pub fn new(root: I::GenericArg) -> Self {
|
||||
Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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<T, A: Allocator> Vec<T, A> {
|
|||
#[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<T, A: Allocator> Vec<T, A> {
|
|||
#[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<T>, 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<T, A: Allocator> Vec<T, A> {
|
|||
#[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<T, A: Allocator> Vec<T, A> {
|
|||
/// 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.
|
||||
|
|
|
|||
|
|
@ -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<T, I, const N: usize> Index<I> for [T; N]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I, const N: usize> const Index<I> for [T; N]
|
||||
where
|
||||
[T]: Index<I>,
|
||||
[T]: ~const Index<I>,
|
||||
{
|
||||
type Output = <[T] as Index<I>>::Output;
|
||||
|
||||
|
|
@ -387,9 +388,10 @@ where
|
|||
}
|
||||
|
||||
#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
|
||||
impl<T, I, const N: usize> IndexMut<I> for [T; N]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I, const N: usize> const IndexMut<I> for [T; N]
|
||||
where
|
||||
[T]: IndexMut<I>,
|
||||
[T]: ~const IndexMut<I>,
|
||||
{
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@
|
|||
#[doc(alias = "]")]
|
||||
#[doc(alias = "[")]
|
||||
#[doc(alias = "[]")]
|
||||
#[const_trait]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub trait Index<Idx: ?Sized> {
|
||||
/// The returned type after indexing.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -165,7 +167,9 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
|
|||
#[doc(alias = "[")]
|
||||
#[doc(alias = "]")]
|
||||
#[doc(alias = "[]")]
|
||||
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[const_trait]
|
||||
pub trait IndexMut<Idx: ?Sized>: ~const Index<Idx> {
|
||||
/// Performs the mutable indexing (`container[index]`) operation.
|
||||
///
|
||||
/// # Panics
|
||||
|
|
|
|||
|
|
@ -1524,10 +1524,11 @@ impl<T> *const [T] {
|
|||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "slice_ptr_get", issue = "74265")]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[inline]
|
||||
pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
|
||||
pub const unsafe fn get_unchecked<I>(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) }
|
||||
|
|
|
|||
|
|
@ -1881,10 +1881,11 @@ impl<T> *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<I>(self, index: I) -> *mut I::Output
|
||||
pub const unsafe fn get_unchecked_mut<I>(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) }
|
||||
|
|
|
|||
|
|
@ -1597,10 +1597,11 @@ impl<T> NonNull<[T]> {
|
|||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "slice_ptr_get", issue = "74265")]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
#[inline]
|
||||
pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
|
||||
pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -186,14 +186,17 @@ impl<T> IntoBounds<T> for Range<T> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<Range<T>> for legacy::Range<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<Range<T>> for legacy::Range<T> {
|
||||
#[inline]
|
||||
fn from(value: Range<T>) -> Self {
|
||||
Self { start: value.start, end: value.end }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<legacy::Range<T>> for Range<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<legacy::Range<T>> for Range<T> {
|
||||
#[inline]
|
||||
fn from(value: legacy::Range<T>) -> Self {
|
||||
Self { start: value.start, end: value.end }
|
||||
|
|
@ -362,7 +365,8 @@ impl<T> IntoBounds<T> for RangeInclusive<T> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
|
||||
#[inline]
|
||||
fn from(value: RangeInclusive<T>) -> Self {
|
||||
Self::new(value.start, value.end)
|
||||
|
|
@ -506,14 +510,16 @@ impl<T> IntoBounds<T> for RangeFrom<T> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<RangeFrom<T>> for legacy::RangeFrom<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> {
|
||||
#[inline]
|
||||
fn from(value: RangeFrom<T>) -> Self {
|
||||
Self { start: value.start }
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
impl<T> From<legacy::RangeFrom<T>> for RangeFrom<T> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> {
|
||||
#[inline]
|
||||
fn from(value: legacy::RangeFrom<T>) -> Self {
|
||||
Self { start: value.start }
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition;
|
|||
use crate::{ops, range};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, I> ops::Index<I> for [T]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I> const ops::Index<I> 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<T, I> ops::IndexMut<I> for [T]
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<T, I> const ops::IndexMut<I> 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<T: ?Sized>: 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<T: ?Sized>: 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<T> SliceIndex<[T]> for usize {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for usize {
|
||||
type Output = T;
|
||||
|
||||
#[inline]
|
||||
|
|
@ -278,7 +283,8 @@ unsafe impl<T> SliceIndex<[T]> for usize {
|
|||
|
||||
/// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
|
||||
/// than there are for a general `Range<usize>` (which might be `100..3`).
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -354,7 +360,8 @@ unsafe impl<T> 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<T> SliceIndex<[T]> for ops::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -453,7 +460,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for range::Range<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -491,7 +499,8 @@ unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
|
|||
|
||||
/// 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<T> SliceIndex<[T]> for ops::RangeTo<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -529,7 +538,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
|
|||
|
||||
/// 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<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -574,7 +584,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for range::RangeFrom<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -611,7 +622,8 @@ unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
|
|||
}
|
||||
|
||||
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -650,7 +662,8 @@ unsafe impl<T> 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<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -693,7 +706,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for range::RangeInclusive<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -731,7 +745,8 @@ unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
|
|||
|
||||
/// 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<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -568,9 +568,10 @@ impl<T> [T] {
|
|||
#[rustc_no_implicit_autorefs]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn get<I>(&self, index: I) -> Option<&I::Output>
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const fn get<I>(&self, index: I) -> Option<&I::Output>
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
index.get(self)
|
||||
}
|
||||
|
|
@ -594,9 +595,10 @@ impl<T> [T] {
|
|||
#[rustc_no_implicit_autorefs]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
index.get_mut(self)
|
||||
}
|
||||
|
|
@ -633,9 +635,10 @@ impl<T> [T] {
|
|||
#[inline]
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
// 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> [T] {
|
|||
#[inline]
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
pub const unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
|
||||
where
|
||||
I: SliceIndex<Self>,
|
||||
I: ~const SliceIndex<Self>,
|
||||
{
|
||||
// SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
|
||||
// the slice is dereferenceable because `self` is a safe reference.
|
||||
|
|
|
|||
|
|
@ -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<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
|
||||
pub const fn get<I: ~const SliceIndex<str>>(&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<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
|
||||
pub const fn get_mut<I: ~const SliceIndex<str>>(&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();
|
||||
|
|
|
|||
|
|
@ -49,9 +49,10 @@ impl PartialOrd for str {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I> ops::Index<I> for str
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<I> const ops::Index<I> for str
|
||||
where
|
||||
I: SliceIndex<str>,
|
||||
I: ~const SliceIndex<str>,
|
||||
{
|
||||
type Output = I::Output;
|
||||
|
||||
|
|
@ -62,9 +63,10 @@ where
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I> ops::IndexMut<I> for str
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
impl<I> const ops::IndexMut<I> for str
|
||||
where
|
||||
I: SliceIndex<str>,
|
||||
I: ~const SliceIndex<str>,
|
||||
{
|
||||
#[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<str> for ops::RangeFull {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeFull {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -156,7 +159,8 @@ unsafe impl SliceIndex<str> for ops::RangeFull {
|
|||
/// // &s[3 .. 100];
|
||||
/// ```
|
||||
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
|
||||
unsafe impl SliceIndex<str> for ops::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::Range<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -260,7 +264,8 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::Range<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for range::Range<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -431,7 +436,8 @@ unsafe impl SliceIndex<str> for (ops::Bound<usize>, ops::Bound<usize>) {
|
|||
/// 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<str> for ops::RangeTo<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -499,7 +505,8 @@ unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
|
|||
/// 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<str> for ops::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -554,7 +561,8 @@ unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for range::RangeFrom<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -625,7 +633,8 @@ unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
|
|||
/// 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<str> for ops::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -662,7 +671,8 @@ unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
@ -713,7 +723,8 @@ unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
|
|||
/// (`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<str> for ops::RangeToInclusive<usize> {
|
||||
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
|
||||
unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<T: Approx + Copy>(_x: T) -> T {
|
||||
T::LIM
|
||||
const fn lim_for_ty<T: TestableFloat + Copy>(_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<T>(ten: T, two: T)
|
||||
where
|
||||
T: PartialEq
|
||||
+ Add<Output = T>
|
||||
+ Sub<Output = T>
|
||||
+ Mul<Output = T>
|
||||
+ Div<Output = T>
|
||||
+ Rem<Output = T>
|
||||
+ 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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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<Float> {
|
||||
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: {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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::<usize>();
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -469,6 +469,29 @@ impl<T: 'static> LocalKey<Cell<T>> {
|
|||
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<i32> = 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<T: 'static> LocalKey<RefCell<T>> {
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
// <x_subcommand> {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<PathBuf> = sections.map(|p| PathBuf::from_str(p).unwrap()).collect();
|
||||
|
||||
(cmd, stage, paths)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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 { .. } => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -481,13 +481,6 @@ Arguments:
|
|||
#[arg(value_name = "<PROFILE>|hook|editor|link")]
|
||||
profile: Option<PathBuf>,
|
||||
},
|
||||
/// 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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,7 +216,6 @@ than building it.
|
|||
build.config.cmd,
|
||||
Subcommand::Clean { .. }
|
||||
| Subcommand::Check { .. }
|
||||
| Subcommand::Suggest { .. }
|
||||
| Subcommand::Format { .. }
|
||||
| Subcommand::Setup { .. }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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++"),
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue