Merge from rustc

This commit is contained in:
Oli Scherer 2023-03-23 07:33:19 +00:00
commit 8c8fc361d8
254 changed files with 2436 additions and 1709 deletions

View file

@ -5294,6 +5294,7 @@ name = "rustc_span"
version = "0.0.0"
dependencies = [
"cfg-if",
"indexmap",
"md-5",
"rustc_arena",
"rustc_data_structures",

View file

@ -180,6 +180,12 @@ impl Attribute {
self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
}
pub fn is_proc_macro_attr(&self) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
.any(|kind| self.has_name(*kind))
}
/// Extracts the MetaItem from inside this Attribute.
pub fn meta(&self) -> Option<MetaItem> {
match &self.kind {
@ -627,6 +633,22 @@ pub fn mk_attr_name_value_str(
mk_attr(g, style, path, args, span)
}
pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
attrs.iter().filter(move |attr| attr.has_name(name))
}
pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
filter_by_name(attrs, name).next()
}
pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
find_by_name(attrs, name).and_then(|attr| attr.value_str())
}
pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
find_by_name(attrs, name).is_some()
}
pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
items.iter().any(|item| item.has_name(name))
}

View file

@ -2185,7 +2185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
def_id: self.local_def_id(param.id),
name,
span: self.lower_span(param.span()),
pure_wrt_drop: self.tcx.sess.contains_name(&param.attrs, sym::may_dangle),
pure_wrt_drop: attr::contains_name(&param.attrs, sym::may_dangle),
kind,
colon_span: param.colon_span.map(|s| self.lower_span(s)),
source,

View file

@ -799,11 +799,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
fn visit_item(&mut self, item: &'a Item) {
if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
self.has_proc_macro_decls = true;
}
if self.session.contains_name(&item.attrs, sym::no_mangle) {
if attr::contains_name(&item.attrs, sym::no_mangle) {
self.check_nomangle_item_asciionly(item.ident, item.span);
}
@ -973,7 +973,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
&& !self.session.contains_name(&item.attrs, sym::path)
&& !attr::contains_name(&item.attrs, sym::path)
{
self.check_mod_file_item_asciionly(item.ident);
}
@ -1248,7 +1248,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
if self.session.contains_name(&item.attrs, sym::no_mangle) {
if attr::contains_name(&item.attrs, sym::no_mangle) {
self.check_nomangle_item_asciionly(item.ident, item.span);
}

View file

@ -1,6 +1,6 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd};
use rustc_errors::{Applicability, StashKey};
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
@ -232,7 +232,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
ast::ItemKind::Fn(..) => {
if self.sess.contains_name(&i.attrs, sym::start) {
if attr::contains_name(&i.attrs, sym::start) {
gate_feature_post!(
&self,
start,
@ -245,7 +245,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
ast::ItemKind::Struct(..) => {
for attr in self.sess.filter_by_name(&i.attrs, sym::repr) {
for attr in attr::filter_by_name(&i.attrs, sym::repr) {
for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
if item.has_name(sym::simd) {
gate_feature_post!(
@ -306,7 +306,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
match i.kind {
ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
let links_to_llvm =
link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
if links_to_llvm {

View file

@ -1,6 +1,6 @@
//! Parsing and validation of builtin attributes
use rustc_ast as ast;
use rustc_ast::{self as ast, attr};
use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
use rustc_ast_pretty::pprust;
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
@ -556,8 +556,8 @@ where
(stab, const_stab, body_stab)
}
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
sess.first_attr_value_str_by_name(attrs, sym::crate_name)
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
attr::first_attr_value_str_by_name(attrs, sym::crate_name)
}
#[derive(Clone, Debug)]
@ -1177,7 +1177,7 @@ fn allow_unstable<'a>(
attrs: &'a [Attribute],
symbol: Symbol,
) -> impl Iterator<Item = Symbol> + 'a {
let attrs = sess.filter_by_name(attrs, symbol);
let attrs = attr::filter_by_name(attrs, symbol);
let list = attrs
.filter_map(move |attr| {
attr.meta_item_list().or_else(|| {

View file

@ -120,9 +120,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&& !self.upvars.is_empty()
{
item_msg = access_place_desc;
debug_assert!(
self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
);
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
debug_assert!(is_closure_or_generator(
Place::ty_from(
the_place_err.local,
@ -470,11 +468,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
{
let local_decl = &self.body.local_decls[local];
let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() {
("&", "reference")
} else {
("*const", "pointer")
};
let (pointer_sigil, pointer_desc) =
if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
match self.local_names[local] {
Some(name) if !local_decl.from_compiler_desugaring() => {
@ -1258,7 +1253,7 @@ fn suggest_ampmut<'tcx>(
(
suggestability,
highlight_span,
if local_decl.ty.is_region_ptr() {
if local_decl.ty.is_ref() {
format!("&mut {}", ty_mut.ty)
} else {
format!("*mut {}", ty_mut.ty)

View file

@ -19,7 +19,6 @@ extern crate tracing;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
@ -141,7 +140,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor
debug!("Skipping borrowck because of injected body");
// Let's make up a borrowck result! Fun times!
let result = BorrowCheckResult {
concrete_opaque_types: VecMap::new(),
concrete_opaque_types: FxIndexMap::default(),
closure_requirements: None,
used_mut_upvars: SmallVec::new(),
tainted_by_errors: None,
@ -511,16 +510,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
.as_var()
.unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
if cfg!(debug_assertions) {
if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
let ctxt = get_ctxt_fn();
let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
let prev = var_to_origin.insert(vid, ctxt);
// This only makes sense if not called in a canonicalization context. If this
// ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
// or modify how we track nll region vars for that map.
assert!(matches!(prev, None));
var_to_origin.insert(vid, ctxt);
}
next_region
@ -540,16 +534,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
.as_var()
.unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
if cfg!(debug_assertions) {
if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
let ctxt = get_ctxt_fn();
let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
let prev = var_to_origin.insert(vid, ctxt);
// This only makes sense if not called in a canonicalization context. If this
// ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
// or modify how we track nll region vars for that map.
assert!(matches!(prev, None));
var_to_origin.insert(vid, ctxt);
}
next_region

View file

@ -2,7 +2,7 @@
#![deny(rustc::diagnostic_outside_of_impl)]
//! The entry point of the NLL borrow checker.
use rustc_data_structures::vec_map::VecMap;
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def_id::LocalDefId;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
@ -44,7 +44,7 @@ pub type PoloniusOutput = Output<RustcFacts>;
/// closure requirements to propagate, and any generated errors.
pub(crate) struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>,
pub opaque_type_values: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
pub polonius_input: Option<Box<AllFacts>>,
pub polonius_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
@ -377,7 +377,7 @@ pub(super) fn dump_annotation<'tcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
errors: &mut crate::error::BorrowckErrors<'tcx>,
) {
let tcx = infcx.tcx;

View file

@ -256,11 +256,12 @@ fn sccs_info<'cx, 'tcx>(
let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
var_to_origin_sorted.sort_by_key(|vto| vto.0);
let mut debug_str = "region variables to origins:\n".to_string();
let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
for (reg_var, origin) in var_to_origin_sorted.into_iter() {
debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin));
reg_vars_to_origins_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin));
}
debug!(debug_str);
debug!("{}", reg_vars_to_origins_str);
let num_components = sccs.scc_data().ranges().len();
let mut components = vec![FxIndexSet::default(); num_components];
@ -275,12 +276,12 @@ fn sccs_info<'cx, 'tcx>(
for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
components_str.push_str(&format!(
"{:?}: {:?})",
"{:?}: {:?},\n)",
ConstraintSccIndex::from_usize(scc_idx),
regions_info,
))
}
debug!(components_str);
debug!("{}", components_str);
// calculate the best representative for each component
let components_representatives = components

View file

@ -1,5 +1,4 @@
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
@ -61,9 +60,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
let member_constraints: FxIndexMap<_, _> = self
.member_constraints

View file

@ -10,7 +10,6 @@ use either::Either;
use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
@ -894,7 +893,7 @@ pub(crate) struct MirTypeckResults<'tcx> {
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) opaque_type_values:
VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
}
/// A collection of region constraints that must be satisfied for the

View file

@ -132,9 +132,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
let reg_var =
reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
let prev = var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info));
assert!(matches!(prev, None));
if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
debug!(?reg_var);
var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info));
}
reg
}
@ -149,14 +152,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
let reg_var =
reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
if cfg!(debug_assertions) {
if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
let prev = var_to_origin.insert(reg_var, RegionCtxt::Existential(None));
// It only makes sense to track region vars in non-canonicalization contexts. If this
// ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
// or modify how we track nll region vars for that map.
assert!(matches!(prev, None));
var_to_origin.insert(reg_var, RegionCtxt::Existential(None));
}
reg

View file

@ -1,7 +1,7 @@
use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use rustc_ast as ast;
use rustc_ast::{walk_list, EnumDef, VariantData};
use rustc_ast::{attr, walk_list, EnumDef, VariantData};
use rustc_errors::Applicability;
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
use rustc_span::symbol::Ident;
@ -106,7 +106,7 @@ fn extract_default_variant<'a>(
let default_variants: SmallVec<[_; 1]> = enum_def
.variants
.iter()
.filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default))
.filter(|variant| attr::contains_name(&variant.attrs, kw::Default))
.collect();
let variant = match default_variants.as_slice() {
@ -116,7 +116,7 @@ fn extract_default_variant<'a>(
.variants
.iter()
.filter(|variant| matches!(variant.data, VariantData::Unit(..)))
.filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive));
.filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive));
let mut diag = cx.struct_span_err(trait_span, "no default declared");
diag.help("make a unit variant default by placing `#[default]` above it");
@ -146,7 +146,7 @@ fn extract_default_variant<'a>(
if v.span == variant.span {
None
} else {
Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new()))
Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new()))
}
})
.collect();
@ -174,7 +174,7 @@ fn extract_default_variant<'a>(
return Err(());
}
if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) {
if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
cx.struct_span_err(variant.ident.span, "default variant must be exhaustive")
.span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
.help("consider a manual implementation of `Default`")
@ -191,7 +191,7 @@ fn validate_default_attribute(
default_variant: &rustc_ast::Variant,
) -> Result<(), ()> {
let attrs: SmallVec<[_; 1]> =
cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect();
attr::filter_by_name(&default_variant.attrs, kw::Default).collect();
let attr = match attrs.as_slice() {
[attr] => attr,

View file

@ -1,6 +1,6 @@
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, NodeId};
use rustc_ast::{self as ast, attr, NodeId};
use rustc_ast_pretty::pprust;
use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
@ -34,7 +34,6 @@ enum ProcMacro {
}
struct CollectProcMacros<'a> {
sess: &'a Session,
macros: Vec<ProcMacro>,
in_root: bool,
handler: &'a rustc_errors::Handler,
@ -56,7 +55,6 @@ pub fn inject(
let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
let mut collect = CollectProcMacros {
sess,
macros: Vec::new(),
in_root: true,
handler,
@ -160,7 +158,7 @@ impl<'a> CollectProcMacros<'a> {
impl<'a> Visitor<'a> for CollectProcMacros<'a> {
fn visit_item(&mut self, item: &'a ast::Item) {
if let ast::ItemKind::MacroDef(..) = item.kind {
if self.is_proc_macro_crate && self.sess.contains_name(&item.attrs, sym::macro_export) {
if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
let msg =
"cannot export macro_rules! macros from a `proc-macro` crate type currently";
self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
@ -176,7 +174,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
let mut found_attr: Option<&'a ast::Attribute> = None;
for attr in &item.attrs {
if self.sess.is_proc_macro_attr(&attr) {
if attr.is_proc_macro_attr() {
if let Some(prev_attr) = found_attr {
let prev_item = prev_attr.get_normal_item();
let item = attr.get_normal_item();

View file

@ -1,4 +1,4 @@
use rustc_ast as ast;
use rustc_ast::{self as ast, attr};
use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::ExpansionConfig;
use rustc_session::Session;
@ -16,10 +16,10 @@ pub fn inject(
let edition = sess.parse_sess.edition;
// the first name in this list is the crate name of the crate with the prelude
let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) {
let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
return krate;
} else if sess.contains_name(&krate.attrs, sym::no_std) {
if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
} else if attr::contains_name(&krate.attrs, sym::no_std) {
if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
&[sym::core]
} else {
&[sym::core, sym::compiler_builtins]

View file

@ -1,12 +1,11 @@
/// The expansion from a test function to the appropriate test struct for libtest
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, attr};
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_expand::base::*;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{FileNameDisplayPreference, Span};
use std::iter;
@ -291,14 +290,11 @@ pub fn expand_test_or_bench(
),
),
// ignore: true | false
field(
"ignore",
cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
),
field("ignore", cx.expr_bool(sp, should_ignore(&item)),),
// ignore_message: Some("...") | None
field(
"ignore_message",
if let Some(msg) = should_ignore_message(cx, &item) {
if let Some(msg) = should_ignore_message(&item) {
cx.expr_some(sp, cx.expr_str(sp, msg))
} else {
cx.expr_none(sp)
@ -425,12 +421,12 @@ enum ShouldPanic {
Yes(Option<Symbol>),
}
fn should_ignore(sess: &Session, i: &ast::Item) -> bool {
sess.contains_name(&i.attrs, sym::ignore)
fn should_ignore(i: &ast::Item) -> bool {
attr::contains_name(&i.attrs, sym::ignore)
}
fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> {
match cx.sess.find_by_name(&i.attrs, sym::ignore) {
fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {
match attr::find_by_name(&i.attrs, sym::ignore) {
Some(attr) => {
match attr.meta_item_list() {
// Handle #[ignore(bar = "foo")]
@ -444,7 +440,7 @@ fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> {
}
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
match attr::find_by_name(&i.attrs, sym::should_panic) {
Some(attr) => {
let sd = &cx.sess.parse_sess.span_diagnostic;
@ -510,7 +506,7 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
}
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
let sd = &cx.sess.parse_sess.span_diagnostic;
match &i.kind {
ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {

View file

@ -47,11 +47,11 @@ pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast
// unconditional, so that the attribute is still marked as used in
// non-test builds.
let reexport_test_harness_main =
sess.first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
// Do this here so that the test_runner crate attribute gets marked as used
// even in non-test builds
let test_runner = get_test_runner(sess, span_diagnostic, &krate);
let test_runner = get_test_runner(span_diagnostic, &krate);
if sess.opts.test {
let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
@ -123,7 +123,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let mut item = i.into_inner();
if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) {
if let Some(name) = get_test_name(&item) {
debug!("this is a test item");
let test = Test { span: item.span, ident: item.ident, name };
@ -145,12 +145,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
// Beware, this is duplicated in librustc_passes/entry.rs (with
// `rustc_hir::Item`), so make sure to keep them in sync.
fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPointType {
fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType {
match item.kind {
ast::ItemKind::Fn(..) => {
if sess.contains_name(&item.attrs, sym::start) {
if attr::contains_name(&item.attrs, sym::start) {
EntryPointType::Start
} else if sess.contains_name(&item.attrs, sym::rustc_main) {
} else if attr::contains_name(&item.attrs, sym::rustc_main) {
EntryPointType::RustcMainAttr
} else if item.ident.name == sym::main {
if depth == 0 {
@ -184,7 +184,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
// Remove any #[rustc_main] or #[start] from the AST so it doesn't
// clash with the one we're going to add, but mark it as
// #[allow(dead_code)] to avoid printing warnings.
let item = match entry_point_type(self.sess, &item, self.depth) {
let item = match entry_point_type(&item, self.depth) {
EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
let allow_dead_code = attr::mk_attr_nested_word(
@ -373,16 +373,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
)
}
fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> {
sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
fn get_test_name(i: &ast::Item) -> Option<Symbol> {
attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
}
fn get_test_runner(
sess: &Session,
sd: &rustc_errors::Handler,
krate: &ast::Crate,
) -> Option<ast::Path> {
let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?;
fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
let meta_list = test_attr.meta_item_list()?;
let span = test_attr.span;
match &*meta_list {

View file

@ -1,4 +1,4 @@
use rustc_ast::{AttrStyle, Attribute, MetaItem};
use rustc_ast::{attr, AttrStyle, Attribute, MetaItem};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_feature::AttributeTemplate;
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
@ -36,7 +36,7 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name:
_ => None,
};
if let Some(attrs) = attrs {
if let Some(attr) = ecx.sess.find_by_name(attrs, name) {
if let Some(attr) = attr::find_by_name(attrs, name) {
ecx.parse_sess().buffer_lint(
DUPLICATE_MACRO_ATTRIBUTES,
attr.span,

View file

@ -48,9 +48,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
) -> (Pointer, Value) {
let (ptr, vtable) = 'block: {
if let Abi::Scalar(_) = arg.layout().abi {
'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr()
&& !arg.layout().ty.is_region_ptr()
{
'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
for i in 0..arg.layout().fields.count() {
let field = arg.value_field(fx, mir::Field::new(i));
if !field.layout().is_zst() {

View file

@ -5,12 +5,12 @@ use crate::llvm;
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::value::Value;
use rustc_ast::attr;
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
use rustc_session::config::{CrateType, DebugInfo};
use rustc_span::symbol::sym;
use rustc_span::DebuggerVisualizerType;
@ -87,7 +87,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, '
pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
let omit_gdb_pretty_printer_section =
cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
attr::contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
// To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
// ODR violations at link time, this section will not be emitted for rlibs since

View file

@ -424,7 +424,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
.filter_map(|s| {
let enable_disable = match s.chars().next() {
None => return None,
Some(c @ '+' | c @ '-') => c,
Some(c @ ('+' | '-')) => c,
Some(_) => {
if diagnostics {
sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s });

View file

@ -8,6 +8,7 @@ use crate::{
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
};
use jobserver::{Acquired, Client};
use rustc_ast::attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
@ -447,8 +448,8 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
let sess = tcx.sess;
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins);
let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins);
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins);
let crate_info = CrateInfo::new(tcx, target_cpu);

View file

@ -809,7 +809,7 @@ impl CrateInfo {
.collect();
let local_crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
let windows_subsystem = subsystem.map(|subsystem| {
if subsystem != sym::windows && subsystem != sym::console {
tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });

View file

@ -917,7 +917,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
//
// This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
&& !op.layout.ty.is_region_ptr()
&& !op.layout.ty.is_ref()
{
for i in 0..op.layout.fields.count() {
let field = op.extract_field(bx, i);
@ -959,7 +959,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Immediate(_) => {
// See comment above explaining why we peel these newtypes
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
&& !op.layout.ty.is_region_ptr()
&& !op.layout.ty.is_ref()
{
for i in 0..op.layout.fields.count() {
let field = op.extract_field(bx, i);

View file

@ -2,7 +2,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::{LangItem, CRATE_HIR_ID};
use rustc_middle::mir;
use rustc_middle::mir::interpret::PointerArithmetic;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
use std::borrow::Borrow;
@ -335,8 +335,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
}
#[inline(always)]
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool {
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
}
fn alignment_check_failed(

View file

@ -8,6 +8,7 @@ use std::hash::Hash;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::mir;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_target::abi::{Align, Size};
@ -145,8 +146,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
check: CheckAlignment,
) -> InterpResult<'tcx, ()>;
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
/// Whether to enforce the validity invariant for a specific layout.
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool;
/// Whether function calls should be [ABI](CallAbi)-checked.
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {

View file

@ -461,7 +461,7 @@ where
) -> InterpResult<'tcx> {
self.write_immediate_no_validate(src, dest)?;
if M::enforce_validity(self) {
if M::enforce_validity(self, dest.layout) {
// Data got changed, better make sure it matches the type!
self.validate_operand(&self.place_to_op(dest)?)?;
}
@ -616,7 +616,7 @@ where
) -> InterpResult<'tcx> {
self.copy_op_no_validate(src, dest, allow_transmute)?;
if M::enforce_validity(self) {
if M::enforce_validity(self, dest.layout) {
// Data got changed, better make sure it matches the type!
self.validate_operand(&self.place_to_op(dest)?)?;
}

View file

@ -79,7 +79,6 @@ pub mod sync;
pub mod tiny_list;
pub mod transitive_relation;
pub mod vec_linked_list;
pub mod vec_map;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;

View file

@ -1,192 +0,0 @@
use std::borrow::Borrow;
use std::fmt::Debug;
use std::slice::Iter;
use std::vec::IntoIter;
use crate::stable_hasher::{HashStable, StableHasher};
/// A map type implemented as a vector of pairs `K` (key) and `V` (value).
/// It currently provides a subset of all the map operations, the rest could be added as needed.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct VecMap<K, V>(Vec<(K, V)>);
impl<K, V> VecMap<K, V>
where
K: Debug + PartialEq,
V: Debug,
{
pub fn new() -> Self {
VecMap(Default::default())
}
/// Sets the value of the entry, and returns the entry's old value.
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) {
Some(std::mem::replace(&mut elem.1, v))
} else {
self.0.push((k, v));
None
}
}
/// Removes the entry from the map and returns the removed value
pub fn remove(&mut self, k: &K) -> Option<V> {
self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1)
}
/// Gets a reference to the value in the entry.
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Eq,
{
self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
}
/// Gets a mutable reference to the value in the entry.
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Eq,
{
self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1)
}
/// Returns the any value corresponding to the supplied predicate filter.
///
/// The supplied predicate will be applied to each (key, value) pair and it will return a
/// reference to the values where the predicate returns `true`.
pub fn any_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
}
/// Returns the value corresponding to the supplied predicate filter. It crashes if there's
/// more than one matching element.
///
/// The supplied predicate will be applied to each (key, value) pair and it will return a
/// reference to the value where the predicate returns `true`.
pub fn get_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
let mut filter = self.0.iter().filter(|kv| predicate(kv));
let (_, value) = filter.next()?;
// This should return just one element, otherwise it's a bug
assert!(
filter.next().is_none(),
"Collection {self:#?} should have just one matching element"
);
Some(value)
}
/// Returns `true` if the map contains a value for the specified key.
///
/// The key may be any borrowed form of the map's key type,
/// [`Eq`] on the borrowed form *must* match those for
/// the key type.
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Eq,
{
self.get(k).is_some()
}
/// Returns `true` if the map contains no elements.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> Iter<'_, (K, V)> {
self.into_iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.into_iter()
}
pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) {
self.0.retain(f)
}
}
impl<K, V> Default for VecMap<K, V> {
#[inline]
fn default() -> Self {
Self(Default::default())
}
}
impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
fn from(vec: Vec<(K, V)>) -> Self {
Self(vec)
}
}
impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> {
fn into(self) -> Vec<(K, V)> {
self.0
}
}
impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl<'a, K, V> IntoIterator for &'a VecMap<K, V> {
type Item = &'a (K, V);
type IntoIter = Iter<'a, (K, V)>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut VecMap<K, V> {
type Item = (&'a K, &'a mut V);
type IntoIter = impl Iterator<Item = Self::Item>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut().map(|(k, v)| (&*k, v))
}
}
impl<K, V> IntoIterator for VecMap<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<(K, V)>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<K: PartialEq + Debug, V: Debug> Extend<(K, V)> for VecMap<K, V> {
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
for (k, v) in iter {
self.insert(k, v);
}
}
fn extend_one(&mut self, (k, v): (K, V)) {
self.insert(k, v);
}
fn extend_reserve(&mut self, additional: usize) {
self.0.extend_reserve(additional);
}
}
impl<K, V, CTX> HashStable<CTX> for VecMap<K, V>
where
K: HashStable<CTX> + Eq,
V: HashStable<CTX>,
{
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
self.0.hash_stable(hcx, hasher)
}
}
#[cfg(test)]
mod tests;

View file

@ -1,48 +0,0 @@
use super::*;
impl<K, V> VecMap<K, V> {
fn into_vec(self) -> Vec<(K, V)> {
self.0.into()
}
}
#[test]
fn test_from_iterator() {
assert_eq!(
std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(),
Vec::<(i32, bool)>::new()
);
assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
assert_eq!(
[(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
vec![(1, true), (2, false)]
);
}
#[test]
fn test_into_iterator_owned() {
assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new());
assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]);
assert_eq!(
VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(),
vec![(1, true), (2, false)]
);
}
#[test]
fn test_insert() {
let mut v = VecMap::new();
assert_eq!(v.insert(1, true), None);
assert_eq!(v.insert(2, false), None);
assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]);
assert_eq!(v.insert(1, false), Some(true));
assert_eq!(v.into_vec(), vec![(1, false), (2, false)]);
}
#[test]
fn test_get() {
let v = [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
assert_eq!(v.get(&1), Some(&true));
assert_eq!(v.get(&2), Some(&false));
assert_eq!(v.get(&3), None);
}

View file

@ -15,9 +15,8 @@ or causing an integer overflow are two ways to induce this error.
Ensure that the expressions given can be evaluated as the desired integer type.
See the [Custom Discriminants][custom-discriminants] section of the Reference
for more information about setting custom integer types on fieldless enums
using the [`repr` attribute][repr-attribute].
See the [Discriminants] section of the Reference for more information about
setting custom integer types on enums using the [`repr` attribute][repr-attribute].
[custom-discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations
[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#reprc-enums
[discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#discriminants
[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations

View file

@ -59,6 +59,6 @@ In the definition of `bar`, the lifetime parameter `'a` is late-bound, while
where `'a` is universally quantified and `'b` is substituted by a specific
lifetime. It is not allowed to explicitly specify early-bound lifetime
arguments when late-bound lifetime parameters are present (as for `bar_fn2`,
see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the
see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although the
types that are constrained by early-bound parameters can be specified (as for
`bar_fn3`).

View file

@ -776,16 +776,14 @@ impl SyntaxExtension {
let allow_internal_unstable =
attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>();
let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe);
let local_inner_macros = sess
.find_by_name(attrs, sym::macro_export)
let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe);
let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
.and_then(|macro_export| macro_export.meta_item_list())
.map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros));
let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo);
let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo);
tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
let (builtin_name, helper_attrs) = sess
.find_by_name(attrs, sym::rustc_builtin_macro)
let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro)
.map(|attr| {
// Override `helper_attrs` passed above if it's a built-in macro,
// marking `proc_macro_derive` macros as built-in is not a realistic use case.

View file

@ -301,6 +301,7 @@ language_item_table! {
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
Option, sym::Option, option_type, Target::Enum, GenericRequirement::None;
OptionSome, sym::Some, option_some_variant, Target::Variant, GenericRequirement::None;
OptionNone, sym::None, option_none_variant, Target::Variant, GenericRequirement::None;

View file

@ -31,6 +31,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::DynKind;
use rustc_middle::ty::GenericParamDefKind;
@ -2225,47 +2226,66 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let param_env = tcx.param_env(block.owner.to_def_id());
let cause = ObligationCause::misc(span, block.owner.def_id);
let mut fulfillment_errors = Vec::new();
let mut applicable_candidates: Vec<_> = candidates
.iter()
.filter_map(|&(impl_, (assoc_item, def_scope))| {
infcx.probe(|_| {
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
let mut applicable_candidates: Vec<_> = infcx.probe(|_| {
let universe = infcx.create_next_universe();
let impl_ty = tcx.type_of(impl_);
let impl_substs = infcx.fresh_item_substs(impl_);
let impl_ty = impl_ty.subst(tcx, impl_substs);
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
// Regions are not considered during selection.
let self_ty = tcx.replace_escaping_bound_vars_uncached(
self_ty,
FnMutDelegate {
regions: &mut |_| tcx.lifetimes.re_erased,
types: &mut |bv| {
tcx.mk_placeholder(ty::PlaceholderType { universe, name: bv.kind })
},
consts: &mut |bv, ty| {
tcx.mk_const(ty::PlaceholderConst { universe, name: bv }, ty)
},
},
);
// Check that the Self-types can be related.
// FIXME(fmease): Should we use `eq` here?
ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
candidates
.iter()
.filter_map(|&(impl_, (assoc_item, def_scope))| {
infcx.probe(|_| {
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
// Check whether the impl imposes obligations we have to worry about.
let impl_bounds = tcx.predicates_of(impl_);
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
let impl_ty = tcx.type_of(impl_);
let impl_substs = infcx.fresh_item_substs(impl_);
let impl_ty = impl_ty.subst(tcx, impl_substs);
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
// Check that the Self-types can be related.
// FIXME(fmease): Should we use `eq` here?
ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
let impl_obligations = traits::predicates_for_generics(
|_, _| cause.clone(),
param_env,
impl_bounds,
);
// Check whether the impl imposes obligations we have to worry about.
let impl_bounds = tcx.predicates_of(impl_);
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
ocx.register_obligations(impl_obligations);
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
let mut errors = ocx.select_where_possible();
if !errors.is_empty() {
fulfillment_errors.append(&mut errors);
return None;
}
let impl_obligations = traits::predicates_for_generics(
|_, _| cause.clone(),
param_env,
impl_bounds,
);
// FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
ocx.register_obligations(impl_obligations);
let mut errors = ocx.select_where_possible();
if !errors.is_empty() {
fulfillment_errors.append(&mut errors);
return None;
}
// FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
})
})
})
.collect();
.collect()
});
if applicable_candidates.len() > 1 {
return Err(self.complain_about_ambiguous_inherent_assoc_type(

View file

@ -305,7 +305,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
}) = item.kind
{
let substs = InternalSubsts::identity_for_item(tcx, def_id);
let opaque_identity_ty = if in_trait {
let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
tcx.mk_projection(def_id.to_def_id(), substs)
} else {
tcx.mk_opaque(def_id.to_def_id(), substs)
@ -554,7 +554,15 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
check_union(tcx, id.owner_id.def_id);
}
DefKind::OpaqueTy => {
check_opaque(tcx, id);
let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty();
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
{
// Skip opaques from RPIT in traits with no default body.
} else {
check_opaque(tcx, id);
}
}
DefKind::ImplTraitPlaceholder => {
let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id());

View file

@ -223,6 +223,21 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
],
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
),
sym::option_payload_ptr => {
let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None);
let p0 = param(0);
(
1,
vec![tcx.mk_ptr(ty::TypeAndMut {
ty: tcx.mk_adt(
tcx.adt_def(option_def_id),
tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()),
),
mutbl: hir::Mutability::Not,
})],
tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }),
)
}
sym::ptr_mask => (
1,
vec![

View file

@ -202,8 +202,11 @@ fn missing_items_err(
missing_items: &[ty::AssocItem],
full_impl_span: Span,
) {
let missing_items =
missing_items.iter().filter(|trait_item| tcx.opt_rpitit_info(trait_item.def_id).is_none());
let missing_items_msg = missing_items
.iter()
.clone()
.map(|trait_item| trait_item.name.to_string())
.collect::<Vec<_>>()
.join("`, `");

View file

@ -1208,7 +1208,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
fn_sig,
Applicability::MachineApplicable,
);
} else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) {
} else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) {
diag.span_suggestion(
ty.span,
"replace with an appropriate return type",
@ -1240,12 +1240,10 @@ fn infer_return_ty_for_fn_sig<'tcx>(
}
}
// FIXME(vincenzopalazzo): remove the hir item when the refactoring is stable
fn suggest_impl_trait<'tcx>(
tcx: TyCtxt<'tcx>,
ret_ty: Ty<'tcx>,
span: Span,
_hir_id: hir::HirId,
def_id: LocalDefId,
) -> Option<String> {
let format_as_assoc: fn(_, _, _, _, _) -> _ =

View file

@ -778,7 +778,7 @@ fn find_opaque_ty_constraints_for_rpit(
// Use borrowck to get the type with unerased regions.
let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
debug!(?concrete_opaque_types);
for &(def_id, concrete_type) in concrete_opaque_types {
for (&def_id, &concrete_type) in concrete_opaque_types {
if def_id != self.def_id {
// Ignore constraints for other opaque types.
continue;

View file

@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
let deref_kind = if checked_ty.is_box() {
"unboxing the value"
} else if checked_ty.is_region_ptr() {
} else if checked_ty.is_ref() {
"dereferencing the borrow"
} else {
"dereferencing the type"

View file

@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = ensure_sufficient_stack(|| match &expr.kind {
hir::ExprKind::Path(
qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..),
qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
) => self.check_expr_path(qpath, expr, args),
_ => self.check_expr_kind(expr, expected),
});

View file

@ -165,8 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
ty: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
self.err_ctxt().extract_callable_info(body_hir_id, self.param_env, ty)
self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
}
pub fn suggest_two_fn_call(

View file

@ -1182,7 +1182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.inputs()
.skip_binder()
.get(0)
.filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
.filter(|ty| ty.is_ref() && !rcvr_ty.is_ref())
.copied()
.unwrap_or(rcvr_ty),
};

View file

@ -30,6 +30,8 @@ use super::*;
use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject};
use std::cell::Cell;
/// Whether we should define opaque types or just treat them opaquely.
///
/// Currently only used to prevent predicate matching from matching anything
@ -82,6 +84,7 @@ impl<'tcx> InferCtxt<'tcx> {
in_snapshot: self.in_snapshot.clone(),
universe: self.universe.clone(),
intercrate: self.intercrate,
inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()),
}
}
}

View file

@ -561,6 +561,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt();
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::NEEDS_INFER |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`

View file

@ -159,9 +159,7 @@ impl<'tcx> InferCtxt<'tcx> {
.opaque_type_storage
.opaque_types
.iter()
.map(|&(k, ref v)| {
(self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)
})
.map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
.collect()
}

View file

@ -39,6 +39,7 @@ use rustc_span::Span;
use std::cell::{Cell, RefCell};
use std::fmt;
use std::ops::Drop;
use self::combine::CombineFields;
use self::error_reporting::TypeErrCtxt;
@ -342,6 +343,11 @@ pub struct InferCtxt<'tcx> {
/// there is no type that the user could *actually name* that
/// would satisfy it. This avoids crippling inference, basically.
pub intercrate: bool,
/// Flag that is set when we enter canonicalization. Used for debugging to ensure
/// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin`
/// inside non-canonicalization contexts.
inside_canonicalization_ctxt: Cell<bool>,
}
/// See the `error_reporting` module for more details.
@ -585,8 +591,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
self
}
pub fn intercrate(mut self) -> Self {
self.intercrate = true;
pub fn intercrate(mut self, intercrate: bool) -> Self {
self.intercrate = intercrate;
self
}
@ -633,6 +639,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
skip_leak_check: Cell::new(false),
universe: Cell::new(ty::UniverseIndex::ROOT),
intercrate,
inside_canonicalization_ctxt: Cell::new(false),
}
}
}
@ -1728,6 +1735,31 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
}
pub fn inside_canonicalization_ctxt(&self) -> bool {
self.inside_canonicalization_ctxt.get()
}
pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> {
let prev_ctxt = self.inside_canonicalization_ctxt();
self.inside_canonicalization_ctxt.set(true);
CanonicalizationCtxtGuard { prev_ctxt, infcx: self }
}
fn set_canonicalization_ctxt_to(&self, ctxt: bool) {
self.inside_canonicalization_ctxt.set(ctxt);
}
}
pub struct CanonicalizationCtxtGuard<'cx, 'tcx> {
prev_ctxt: bool,
infcx: &'cx InferCtxt<'tcx>,
}
impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> {
fn drop(&mut self) {
self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt)
}
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {

View file

@ -28,6 +28,7 @@ use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
@ -55,21 +56,6 @@ where
ambient_variance: ty::Variance,
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
/// When we pass through a set of binders (e.g., when looking into
/// a `fn` type), we push a new bound region scope onto here. This
/// will contain the instantiated region for each region in those
/// binders. When we then encounter a `ReLateBound(d, br)`, we can
/// use the De Bruijn index `d` to find the right scope, and then
/// bound region name `br` to find the specific instantiation from
/// within that scope. See `replace_bound_region`.
///
/// This field stores the instantiations for late-bound regions in
/// the `a` type.
a_scopes: Vec<BoundRegionScope<'tcx>>,
/// Same as `a_scopes`, but for the `b` type.
b_scopes: Vec<BoundRegionScope<'tcx>>,
}
pub trait TypeRelatingDelegate<'tcx> {
@ -147,8 +133,6 @@ where
delegate,
ambient_variance,
ambient_variance_info: ty::VarianceDiagInfo::default(),
a_scopes: vec![],
b_scopes: vec![],
}
}
@ -166,88 +150,6 @@ where
}
}
fn create_scope(
&mut self,
value: ty::Binder<'tcx, impl Relate<'tcx>>,
universally_quantified: UniversallyQuantified,
) -> BoundRegionScope<'tcx> {
let mut scope = BoundRegionScope::default();
// Create a callback that creates (via the delegate) either an
// existential or placeholder region as needed.
let mut next_region = {
let delegate = &mut self.delegate;
let mut lazy_universe = None;
move |br: ty::BoundRegion| {
if universally_quantified.0 {
// The first time this closure is called, create a
// new universe for the placeholders we will make
// from here out.
let universe = lazy_universe.unwrap_or_else(|| {
let universe = delegate.create_next_universe();
lazy_universe = Some(universe);
universe
});
let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
delegate.next_placeholder_region(placeholder)
} else {
delegate.next_existential_region_var(true, br.kind.get_name())
}
}
};
value.skip_binder().visit_with(&mut ScopeInstantiator {
next_region: &mut next_region,
target_index: ty::INNERMOST,
bound_region_scope: &mut scope,
});
scope
}
/// When we encounter binders during the type traversal, we record
/// the value to substitute for each of the things contained in
/// that binder. (This will be either a universal placeholder or
/// an existential inference variable.) Given the De Bruijn index
/// `debruijn` (and name `br`) of some binder we have now
/// encountered, this routine finds the value that we instantiated
/// the region with; to do so, it indexes backwards into the list
/// of ambient scopes `scopes`.
fn lookup_bound_region(
debruijn: ty::DebruijnIndex,
br: &ty::BoundRegion,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope<'tcx>],
) -> ty::Region<'tcx> {
// The debruijn index is a "reverse index" into the
// scopes listing. So when we have INNERMOST (0), we
// want the *last* scope pushed, and so forth.
let debruijn_index = debruijn.index() - first_free_index.index();
let scope = &scopes[scopes.len() - debruijn_index - 1];
// Find this bound region in that scope to map to a
// particular region.
scope.map[br]
}
/// If `r` is a bound region, find the scope in which it is bound
/// (from `scopes`) and return the value that we instantiated it
/// with. Otherwise just return `r`.
fn replace_bound_region(
&self,
r: ty::Region<'tcx>,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope<'tcx>],
) -> ty::Region<'tcx> {
debug!("replace_bound_regions(scopes={:?})", scopes);
if let ty::ReLateBound(debruijn, br) = *r {
Self::lookup_bound_region(debruijn, &br, first_free_index, scopes)
} else {
r
}
}
/// Push a new outlives requirement into our output set of
/// constraints.
fn push_outlives(
@ -314,18 +216,9 @@ where
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
// The generalized values we extract from `canonical_var_values` have
// been fully instantiated and hence the set of scopes we have
// doesn't matter -- just to be sure, put an empty vector
// in there.
let old_a_scopes = std::mem::take(pair.vid_scopes(self));
// Relate the generalized kind to the original one.
let result = pair.relate_generalized_ty(self, generalized_ty);
// Restore the old scopes now.
*pair.vid_scopes(self) = old_a_scopes;
debug!("relate_ty_var: complete, result = {:?}", result);
result
}
@ -379,6 +272,97 @@ where
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
Ok(a)
}
#[instrument(skip(self), level = "debug")]
fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
where
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
{
if let Some(inner) = binder.no_bound_vars() {
return inner;
}
let mut next_region = {
let nll_delegate = &mut self.delegate;
let mut lazy_universe = None;
move |br: ty::BoundRegion| {
// The first time this closure is called, create a
// new universe for the placeholders we will make
// from here out.
let universe = lazy_universe.unwrap_or_else(|| {
let universe = nll_delegate.create_next_universe();
lazy_universe = Some(universe);
universe
});
let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
debug!(?placeholder);
let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
debug!(?placeholder_reg);
placeholder_reg
}
};
let delegate = FnMutDelegate {
regions: &mut next_region,
types: &mut |_bound_ty: ty::BoundTy| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_var: ty::BoundVar, _ty| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};
let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
debug!(?replaced);
replaced
}
#[instrument(skip(self), level = "debug")]
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
where
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
{
if let Some(inner) = binder.no_bound_vars() {
return inner;
}
let mut next_region = {
let nll_delegate = &mut self.delegate;
let mut reg_map = FxHashMap::default();
move |br: ty::BoundRegion| {
if let Some(ex_reg_var) = reg_map.get(&br) {
return *ex_reg_var;
} else {
let ex_reg_var =
nll_delegate.next_existential_region_var(true, br.kind.get_name());
debug!(?ex_reg_var);
reg_map.insert(br, ex_reg_var);
ex_reg_var
}
}
};
let delegate = FnMutDelegate {
regions: &mut next_region,
types: &mut |_bound_ty: ty::BoundTy| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_var: ty::BoundVar, _ty| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};
let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
debug!(?replaced);
replaced
}
}
/// When we instantiate an inference variable with a value in
@ -396,14 +380,6 @@ trait VidValuePair<'tcx>: Debug {
/// opposite part of the tuple from the vid).
fn value_ty(&self) -> Ty<'tcx>;
/// Extract the scopes that apply to whichever side of the tuple
/// the vid was found on. See the comment where this is called
/// for more details on why we want them.
fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>(
&self,
relate: &'r mut TypeRelating<'_, 'tcx, D>,
) -> &'r mut Vec<BoundRegionScope<'tcx>>;
/// Given a generalized type G that should replace the vid, relate
/// G to the value, putting G on whichever side the vid would have
/// appeared.
@ -425,16 +401,6 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) {
self.1
}
fn vid_scopes<'r, D>(
&self,
relate: &'r mut TypeRelating<'_, 'tcx, D>,
) -> &'r mut Vec<BoundRegionScope<'tcx>>
where
D: TypeRelatingDelegate<'tcx>,
{
&mut relate.a_scopes
}
fn relate_generalized_ty<D>(
&self,
relate: &mut TypeRelating<'_, 'tcx, D>,
@ -457,16 +423,6 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) {
self.0
}
fn vid_scopes<'r, D>(
&self,
relate: &'r mut TypeRelating<'_, 'tcx, D>,
) -> &'r mut Vec<BoundRegionScope<'tcx>>
where
D: TypeRelatingDelegate<'tcx>,
{
&mut relate.b_scopes
}
fn relate_generalized_ty<D>(
&self,
relate: &mut TypeRelating<'_, 'tcx, D>,
@ -602,20 +558,14 @@ where
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!(?self.ambient_variance);
let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
debug!(?v_a);
debug!(?v_b);
if self.ambient_covariance() {
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
self.push_outlives(v_a, v_b, self.ambient_variance_info);
self.push_outlives(a, b, self.ambient_variance_info);
}
if self.ambient_contravariance() {
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
self.push_outlives(v_b, v_a, self.ambient_variance_info);
self.push_outlives(b, a, self.ambient_variance_info);
}
Ok(a)
@ -689,15 +639,6 @@ where
// instantiation of B (i.e., B instantiated with
// universals).
let b_scope = self.create_scope(b, UniversallyQuantified(true));
let a_scope = self.create_scope(a, UniversallyQuantified(false));
debug!(?a_scope, "(existential)");
debug!(?b_scope, "(universal)");
self.b_scopes.push(b_scope);
self.a_scopes.push(a_scope);
// Reset the ambient variance to covariant. This is needed
// to correctly handle cases like
//
@ -718,12 +659,14 @@ where
// subtyping (i.e., `&'b u32 <: &{P} u32`).
let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
self.relate(a.skip_binder(), b.skip_binder())?;
// Note: the order here is important. Create the placeholders first, otherwise
// we assign the wrong universe to the existential!
let b_replaced = self.instantiate_binder_with_placeholders(b);
let a_replaced = self.instantiate_binder_with_existentials(a);
self.relate(a_replaced, b_replaced)?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
if self.ambient_contravariance() {
@ -733,26 +676,17 @@ where
// instantiation of B (i.e., B instantiated with
// existentials). Opposite of above.
let a_scope = self.create_scope(a, UniversallyQuantified(true));
let b_scope = self.create_scope(b, UniversallyQuantified(false));
debug!(?a_scope, "(universal)");
debug!(?b_scope, "(existential)");
self.a_scopes.push(a_scope);
self.b_scopes.push(b_scope);
// Reset ambient variance to contravariance. See the
// covariant case above for an explanation.
let variance =
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
self.relate(a.skip_binder(), b.skip_binder())?;
let a_replaced = self.instantiate_binder_with_placeholders(a);
let b_replaced = self.instantiate_binder_with_existentials(b);
self.relate(a_replaced, b_replaced)?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
Ok(a)

View file

@ -5,8 +5,8 @@ use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits;
use hir::def_id::{DefId, LocalDefId};
use hir::OpaqueTyOrigin;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@ -21,7 +21,7 @@ use std::ops::ControlFlow;
mod table;
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
/// Information about the opaque types whose values we

View file

@ -1,3 +1,4 @@
use rustc_ast::attr;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
@ -8,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
for id in tcx.hir().items() {
let attrs = tcx.hir().attrs(id.hir_id());
if tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
if attr::contains_name(attrs, sym::rustc_proc_macro_decls) {
decls = Some(id.owner_id.def_id);
}
}

View file

@ -505,7 +505,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
.opts
.crate_name
.clone()
.or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string()))
.or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()))
.unwrap_or_else(|| sess.io.input.filestem().to_owned());
OutputFilenames::new(

View file

@ -358,29 +358,29 @@ impl EarlyLintPass for UnsafeCode {
}
ast::ItemKind::Fn(..) => {
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn);
}
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn);
}
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
}
}
ast::ItemKind::Static(..) => {
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic);
}
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic);
}
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic);
}
}
@ -391,10 +391,10 @@ impl EarlyLintPass for UnsafeCode {
fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
if let ast::AssocItemKind::Fn(..) = it.kind {
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod);
}
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
}
}
@ -1123,12 +1123,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
};
match it.kind {
hir::ItemKind::Fn(.., ref generics, _) => {
if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) {
if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
}
}
hir::ItemKind::Const(..) => {
if cx.sess().contains_name(attrs, sym::no_mangle) {
if attr::contains_name(attrs, sym::no_mangle) {
// account for "pub const" (#45562)
let start = cx
.tcx
@ -1152,9 +1152,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
for it in *items {
if let hir::AssocItemKind::Fn { .. } = it.kind {
if let Some(no_mangle_attr) = cx
.sess()
.find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
if let Some(no_mangle_attr) =
attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
{
check_no_mangle_on_generic_fn(
no_mangle_attr,
@ -1836,7 +1835,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
}
let attrs = cx.tcx.hir().attrs(it.hir_id());
if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) {
cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems);
}
}

View file

@ -328,8 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
Some(Ident::from_str(name))
} else {
cx.sess()
.find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
.and_then(|attr| attr.meta())
.and_then(|meta| {
meta.name_value_literal().and_then(|lit| {
@ -489,7 +488,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(it.hir_id());
match it.kind {
hir::ItemKind::Static(..) if !cx.sess().contains_name(attrs, sym::no_mangle) => {
hir::ItemKind::Static(..) if !attr::contains_name(attrs, sym::no_mangle) => {
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
}
hir::ItemKind::Const(..) => {

View file

@ -6,11 +6,11 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_ast::{self as ast, *};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard};
use rustc_expand::base::SyntaxExtension;
use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::TyCtxt;
@ -46,9 +46,8 @@ pub struct CStore {
/// This crate has a `#[alloc_error_handler]` item.
has_alloc_error_handler: bool,
/// This map is used to verify we get no hash conflicts between
/// `StableCrateId` values.
pub(crate) stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
/// The interned [StableCrateId]s.
pub(crate) stable_crate_ids: StableCrateIdMap,
/// Unused externs of the crate
unused_externs: Vec<Symbol>,
@ -144,9 +143,21 @@ impl CStore {
})
}
fn alloc_new_crate_num(&mut self) -> CrateNum {
self.metas.push(None);
CrateNum::new(self.metas.len() - 1)
fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError> {
assert_eq!(self.metas.len(), self.stable_crate_ids.len());
let num = CrateNum::new(self.stable_crate_ids.len());
if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) {
let crate_name0 = root.name();
if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) {
Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
} else {
Err(CrateError::SymbolConflictsCurrent(crate_name0))
}
} else {
self.metas.push(None);
self.stable_crate_ids.insert(root.stable_crate_id(), num);
Ok(num)
}
}
pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
@ -247,7 +258,7 @@ impl CStore {
}
pub fn new(sess: &Session) -> CStore {
let mut stable_crate_ids = FxHashMap::default();
let mut stable_crate_ids = StableCrateIdMap::default();
stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
CStore {
// We add an empty entry for LOCAL_CRATE (which maps to zero) in
@ -342,42 +353,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
None
}
fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> {
// Check for (potential) conflicts with the local crate
if self.sess.local_stable_crate_id() == root.stable_crate_id() {
return Err(CrateError::SymbolConflictsCurrent(root.name()));
}
// Check for conflicts with any crate loaded so far
for (_, other) in self.cstore.iter_crate_data() {
// Same stable crate id but different SVH
if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() {
bug!(
"Previously returned E0523 here. \
See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\
root.name() = {}.",
root.name()
);
}
}
Ok(())
}
fn verify_no_stable_crate_id_hash_conflicts(
&mut self,
root: &CrateRoot,
cnum: CrateNum,
) -> Result<(), CrateError> {
if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) {
let crate_name0 = root.name();
let crate_name1 = self.cstore.get_crate_data(existing).name();
return Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1));
}
Ok(())
}
fn register_crate(
&mut self,
host_lib: Option<Library>,
@ -396,7 +371,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep);
// Claim this crate number and cache it
let cnum = self.cstore.alloc_new_crate_num();
let cnum = self.cstore.intern_stable_crate_id(&crate_root)?;
info!(
"register crate `{}` (cnum = {}. private_dep = {})",
@ -432,14 +407,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
None
};
// Perform some verification *after* resolve_crate_deps() above is
// known to have been successful. It seems that - in error cases - the
// cstore can be in a temporarily invalid state between cnum allocation
// and dependency resolution and the verification code would produce
// ICEs in that case (see #83045).
self.verify_no_symbol_conflicts(&crate_root)?;
self.verify_no_stable_crate_id_hash_conflicts(&crate_root, cnum)?;
let crate_metadata = CrateMetadata::new(
self.sess,
&self.cstore,
@ -720,8 +687,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
// compilation mode also comes into play.
let desired_strategy = self.sess.panic_strategy();
let mut runtime_found = false;
let mut needs_panic_runtime =
self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime);
let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
for (cnum, data) in self.cstore.iter_crate_data() {
needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
@ -789,7 +755,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
info!("loading profiler");
let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
if name == sym::profiler_builtins && attr::contains_name(&krate.attrs, sym::no_core) {
self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore);
}
@ -803,14 +769,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
self.cstore.has_global_allocator = match &*global_allocator_spans(krate) {
[span1, span2, ..] => {
self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
true
}
spans => !spans.is_empty(),
};
self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) {
self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) {
[span1, span2, ..] => {
self.sess
.emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
@ -822,7 +788,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
// Check to see if we actually need an allocator. This desire comes
// about through the `#![needs_allocator]` attribute and is typically
// written down in liballoc.
if !self.sess.contains_name(&krate.attrs, sym::needs_allocator)
if !attr::contains_name(&krate.attrs, sym::needs_allocator)
&& !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
{
return;
@ -881,7 +847,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
// allocator. At this point our allocator request is typically fulfilled
// by the standard library, denoted by the `#![default_lib_allocator]`
// attribute.
if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
&& !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
{
self.sess.emit_err(errors::GlobalAllocRequired);
@ -1003,7 +969,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
None => item.ident.name,
};
let dep_kind = if self.sess.contains_name(&item.attrs, sym::no_link) {
let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
CrateDepKind::MacrosOnly
} else {
CrateDepKind::Explicit
@ -1049,16 +1015,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
}
fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
struct Finder<'a> {
sess: &'a Session,
fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
struct Finder {
name: Symbol,
spans: Vec<Span>,
}
impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
impl<'ast> visit::Visitor<'ast> for Finder {
fn visit_item(&mut self, item: &'ast ast::Item) {
if item.ident.name == self.name
&& self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
&& attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
{
self.spans.push(item.span);
}
@ -1067,21 +1032,20 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
}
let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
let mut f = Finder { sess, name, spans: Vec::new() };
let mut f = Finder { name, spans: Vec::new() };
visit::walk_crate(&mut f, krate);
f.spans
}
fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
struct Finder<'a> {
sess: &'a Session,
fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
struct Finder {
name: Symbol,
spans: Vec<Span>,
}
impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
impl<'ast> visit::Visitor<'ast> for Finder {
fn visit_item(&mut self, item: &'ast ast::Item) {
if item.ident.name == self.name
&& self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
&& attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
{
self.spans.push(item.span);
}
@ -1090,7 +1054,7 @@ fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
}
let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
let mut f = Finder { sess, name, spans: Vec::new() };
let mut f = Finder { name, spans: Vec::new() };
visit::walk_crate(&mut f, krate);
f.spans
}

View file

@ -1709,10 +1709,6 @@ impl CrateMetadata {
self.root.name
}
pub(crate) fn stable_crate_id(&self) -> StableCrateId {
self.root.stable_crate_id
}
pub(crate) fn hash(&self) -> Svh {
self.root.hash
}

View file

@ -595,7 +595,10 @@ impl CrateStore for CStore {
}
fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum {
self.stable_crate_ids[&stable_crate_id]
*self
.stable_crate_ids
.get(&stable_crate_id)
.unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}"))
}
/// Returns the `DefKey` for a given `DefId`. This indicates the

View file

@ -681,17 +681,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
has_default_lib_allocator: tcx
.sess
.contains_name(&attrs, sym::default_lib_allocator),
has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator),
proc_macro_data,
debugger_visualizers,
compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins),
needs_allocator: attr::contains_name(&attrs, sym::needs_allocator),
needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime),
no_builtins: attr::contains_name(&attrs, sym::no_builtins),
panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
crate_deps,
@ -1016,7 +1014,6 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
| DefKind::Const
| DefKind::Static(..)
| DefKind::TyAlias
| DefKind::OpaqueTy
| DefKind::ForeignTy
| DefKind::Impl { .. }
| DefKind::AssocFn
@ -1027,6 +1024,18 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
| DefKind::AnonConst
| DefKind::InlineConst => true,
DefKind::OpaqueTy => {
let opaque = tcx.hir().expect_item(def_id).expect_opaque_ty();
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
{
false
} else {
true
}
}
DefKind::ImplTraitPlaceholder => {
let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id());
let assoc_item = tcx.associated_item(parent_def_id);
@ -1044,7 +1053,13 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
let assoc_item = tcx.associated_item(def_id);
match assoc_item.container {
ty::AssocItemContainer::ImplContainer => true,
ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(),
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) always encode RPITITs,
// since we need to be able to "project" from an RPITIT associated item
// to an opaque when installing the default projection predicates in
// default trait methods with RPITITs.
ty::AssocItemContainer::TraitContainer => {
assoc_item.defaultness(tcx).has_value() || assoc_item.opt_rpitit_info.is_some()
}
}
}
DefKind::TyParam => {
@ -1730,11 +1745,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Proc-macros may have attributes like `#[allow_internal_unstable]`,
// so downstream crates need access to them.
let attrs = hir.attrs(proc_macro);
let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) {
let macro_kind = if attr::contains_name(attrs, sym::proc_macro) {
MacroKind::Bang
} else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) {
} else if attr::contains_name(attrs, sym::proc_macro_attribute) {
MacroKind::Attr
} else if let Some(attr) = tcx.sess.find_by_name(attrs, sym::proc_macro_derive) {
} else if let Some(attr) = attr::find_by_name(attrs, sym::proc_macro_derive) {
// This unwrap chain should have been checked by the proc-macro harness.
name = attr.meta_item_list().unwrap()[0]
.meta_item()

View file

@ -188,7 +188,7 @@ impl<'hir> Map<'hir> {
ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
ItemKind::Mod(..) => DefKind::Mod,
ItemKind::OpaqueTy(ref opaque) => {
if opaque.in_trait {
if opaque.in_trait && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() {
DefKind::ImplTraitPlaceholder
} else {
DefKind::OpaqueTy

View file

@ -2,8 +2,8 @@
use crate::mir::{Body, ConstantKind, Promoted};
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordSet;
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -227,7 +227,7 @@ pub struct BorrowCheckResult<'tcx> {
/// All the opaque types that are restricted to concrete types
/// by this function. Unlike the value in `TypeckResults`, this has
/// unerased regions.
pub concrete_opaque_types: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
pub tainted_by_errors: Option<ErrorGuaranteed>,

View file

@ -63,15 +63,14 @@ impl Certainty {
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
(Certainty::Yes, Certainty::Maybe(_)) => other,
(Certainty::Maybe(_), Certainty::Yes) => self,
(Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
Certainty::Maybe(MaybeCause::Overflow)
}
// If at least one of the goals is ambiguous, hide the overflow as the ambiguous goal
// may still result in failure.
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(_))
| (Certainty::Maybe(_), Certainty::Maybe(MaybeCause::Ambiguity)) => {
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
Certainty::Maybe(MaybeCause::Ambiguity)
}
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow))
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity))
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
Certainty::Maybe(MaybeCause::Overflow)
}
}
}
}

View file

@ -28,7 +28,7 @@ use crate::ty::{
TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility,
};
use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
use rustc_ast as ast;
use rustc_ast::{self as ast, attr};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::intern::Interned;
@ -2520,9 +2520,9 @@ pub fn provide(providers: &mut ty::query::Providers) {
providers.extern_mod_stmt_cnum =
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.is_panic_runtime =
|tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime);
|tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime);
providers.is_compiler_builtins =
|tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
|tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
providers.has_panic_handler = |tcx, LocalCrate| {
// We want to check if the panic handler was defined in this crate
tcx.lang_items().panic_impl().map_or(false, |did| did.is_local())

View file

@ -2525,7 +2525,7 @@ impl<'tcx> TyCtxt<'tcx> {
ident
}
// FIXME(vincenzoapalzzo): move the HirId to a LocalDefId
// FIXME(vincenzopalazzo): move the HirId to a LocalDefId
pub fn adjust_ident_and_get_scope(
self,
mut ident: Ident,

View file

@ -1925,11 +1925,6 @@ impl<'tcx> Ty<'tcx> {
}
}
#[inline]
pub fn is_region_ptr(self) -> bool {
matches!(self.kind(), Ref(..))
}
#[inline]
pub fn is_mutable_ptr(self) -> bool {
matches!(
@ -1956,7 +1951,7 @@ impl<'tcx> Ty<'tcx> {
/// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
#[inline]
pub fn is_any_ptr(self) -> bool {
self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr()
self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr()
}
#[inline]

View file

@ -8,10 +8,9 @@ use crate::{
},
};
use rustc_data_structures::{
fx::FxHashMap,
fx::{FxHashMap, FxIndexMap},
sync::Lrc,
unord::{UnordItems, UnordSet},
vec_map::VecMap,
};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
@ -155,7 +154,7 @@ pub struct TypeckResults<'tcx> {
/// by this function. We also store the
/// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
/// even if they are only set in dead code (which doesn't show up in MIR).
pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
/// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details.

View file

@ -3,6 +3,7 @@ use crate::build::expr::as_place::PlaceBuilder;
use crate::build::scope::DropKind;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_ast::attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
use rustc_errors::ErrorGuaranteed;
@ -680,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Some functions always have overflow checks enabled,
// however, they may not get codegen'd, depending on
// the settings for the crate they are codegened in.
let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks);
let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
// Respect -C overflow-checks.
check_overflow |= tcx.sess.overflow_checks();
// Constants always need overflow checks.

View file

@ -185,7 +185,7 @@ impl<'tcx> Cx<'tcx> {
if self.typeck_results().is_coercion_cast(source.hir_id) {
// Convert the lexpr to a vexpr.
ExprKind::Use { source: self.mirror_expr(source) }
} else if self.typeck_results().expr_ty(source).is_region_ptr() {
} else if self.typeck_results().expr_ty(source).is_ref() {
// Special cased so that we can type check that the element
// type of the source matches the pointed to type of the
// destination.

View file

@ -180,7 +180,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
}
#[inline(always)]
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
false // for now, we don't enforce validity
}
fn alignment_check_failed(

View file

@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_middle::mir::visit::{MutVisitor, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
@ -548,7 +549,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
unimplemented!()
}
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
unimplemented!()
}
fn alignment_check_failed(

View file

@ -6,6 +6,7 @@ use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::abi::VariantIdx;
pub struct LowerIntrinsics;
@ -191,6 +192,35 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
terminator.kind = TerminatorKind::Goto { target };
}
}
sym::option_payload_ptr => {
if let (Some(target), Some(arg)) = (*target, args[0].place()) {
let ty::RawPtr(ty::TypeAndMut { ty: dest_ty, .. }) =
destination.ty(local_decls, tcx).ty.kind()
else { bug!(); };
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::AddressOf(
Mutability::Not,
arg.project_deeper(
&[
PlaceElem::Deref,
PlaceElem::Downcast(
Some(sym::Some),
VariantIdx::from_u32(1),
),
PlaceElem::Field(Field::from_u32(0), *dest_ty),
],
tcx,
),
),
))),
});
terminator.kind = TerminatorKind::Goto { target };
}
}
_ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
validate_simd_shuffle(tcx, args, terminator.source_info.span);
}

View file

@ -336,7 +336,7 @@ parse_expected_identifier_found_reserved_keyword = expected identifier, found re
parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
parse_expected_identifier = expected identifier
parse_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier
parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
parse_sugg_remove_comma = remove this comma

View file

@ -888,12 +888,12 @@ pub(crate) struct InvalidMetaItem {
#[derive(Subdiagnostic)]
#[suggestion(
parse_sugg_escape_to_use_as_identifier,
parse_sugg_escape_identifier,
style = "verbose",
applicability = "maybe-incorrect",
code = "r#"
)]
pub(crate) struct SuggEscapeToUseAsIdentifier {
pub(crate) struct SuggEscapeIdentifier {
#[primary_span]
pub span: Span,
pub ident_name: String,
@ -937,7 +937,7 @@ impl ExpectedIdentifierFound {
pub(crate) struct ExpectedIdentifier {
pub span: Span,
pub token: Token,
pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
pub suggest_raw: Option<SuggEscapeIdentifier>,
pub suggest_remove_comma: Option<SuggRemoveComma>,
pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
}
@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
#[derive(Subdiagnostic)]
#[help(parse_invalid_identifier_with_leading_number)]
pub(crate) struct HelpIdentifierStartsWithNumber;
pub(crate) struct HelpIdentifierStartsWithNumber {
#[primary_span]
pub num_span: Span,
}
pub(crate) struct ExpectedSemi {
pub span: Span,

View file

@ -6,14 +6,14 @@ use super::{
use crate::errors::{
AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma,
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
};
@ -38,7 +38,7 @@ use rustc_errors::{
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP};
use std::mem::take;
use std::ops::{Deref, DerefMut};
use thin_vec::{thin_vec, ThinVec};
@ -268,7 +268,21 @@ impl<'a> Parser<'a> {
self.sess.source_map().span_to_snippet(span)
}
pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
/// Emits an error with suggestions if an identifier was expected but not found.
///
/// Returns a possibly recovered identifier.
pub(super) fn expected_ident_found(
&mut self,
recover: bool,
) -> PResult<'a, (Ident, /* is_raw */ bool)> {
if let TokenKind::DocComment(..) = self.prev_token.kind {
return Err(DocCommentDoesNotDocumentAnything {
span: self.prev_token.span,
missing_comma: None,
}
.into_diagnostic(&self.sess.span_diagnostic));
}
let valid_follow = &[
TokenKind::Eq,
TokenKind::Colon,
@ -281,31 +295,51 @@ impl<'a> Parser<'a> {
TokenKind::CloseDelim(Delimiter::Parenthesis),
];
let suggest_raw = match self.token.ident() {
Some((ident, false))
if ident.is_raw_guess()
&& self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
{
Some(SuggEscapeToUseAsIdentifier {
span: ident.span.shrink_to_lo(),
// `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
// which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
ident_name: ident.name.to_string(),
})
}
_ => None,
};
let mut recovered_ident = None;
// we take this here so that the correct original token is retained in
// the diagnostic, regardless of eager recovery.
let bad_token = self.token.clone();
let suggest_remove_comma = (self.token == token::Comma
&& self.look_ahead(1, |t| t.is_ident()))
.then_some(SuggRemoveComma { span: self.token.span });
// suggest prepending a keyword in identifier position with `r#`
let suggest_raw = if let Some((ident, false)) = self.token.ident()
&& ident.is_raw_guess()
&& self.look_ahead(1, |t| valid_follow.contains(&t.kind))
{
recovered_ident = Some((ident, true));
let help_cannot_start_number =
self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber);
// `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
// which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
let ident_name = ident.name.to_string();
Some(SuggEscapeIdentifier {
span: ident.span.shrink_to_lo(),
ident_name
})
} else { None };
let suggest_remove_comma =
if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
if recover {
self.bump();
recovered_ident = self.ident_or_err(false).ok();
};
Some(SuggRemoveComma { span: bad_token.span })
} else {
None
};
let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| {
let (invalid, valid) = self.token.span.split_at(len as u32);
recovered_ident = Some((Ident::new(valid_portion, valid), false));
HelpIdentifierStartsWithNumber { num_span: invalid }
});
let err = ExpectedIdentifier {
span: self.token.span,
token: self.token.clone(),
span: bad_token.span,
token: bad_token,
suggest_raw,
suggest_remove_comma,
help_cannot_start_number,
@ -314,6 +348,7 @@ impl<'a> Parser<'a> {
// if the token we have is a `<`
// it *might* be a misplaced generic
// FIXME: could we recover with this?
if self.token == token::Lt {
// all keywords that could have generic applied
let valid_prev_keywords =
@ -364,18 +399,38 @@ impl<'a> Parser<'a> {
}
}
err
if let Some(recovered_ident) = recovered_ident && recover {
err.emit();
Ok(recovered_ident)
} else {
Err(err)
}
}
pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
self.expected_ident_found(false).unwrap_err()
}
/// Checks if the current token is a integer or float literal and looks like
/// it could be a invalid identifier with digits at the start.
pub(super) fn is_lit_bad_ident(&mut self) -> bool {
matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. })
// ensure that the integer literal is followed by a *invalid*
// suffix: this is how we know that it is a identifier with an
// invalid beginning.
if rustc_ast::MetaItemLit::from_token(&self.token).is_none()
)
///
/// Returns the number of characters (bytes) composing the invalid portion
/// of the identifier and the valid portion of the identifier.
pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
// ensure that the integer literal is followed by a *invalid*
// suffix: this is how we know that it is a identifier with an
// invalid beginning.
if let token::Literal(Lit {
kind: token::LitKind::Integer | token::LitKind::Float,
symbol,
suffix,
}) = self.token.kind
&& rustc_ast::MetaItemLit::from_token(&self.token).is_none()
{
Some((symbol.as_str().len(), suffix.unwrap()))
} else {
None
}
}
pub(super) fn expected_one_of_not_found(

View file

@ -1181,7 +1181,7 @@ impl<'a> Parser<'a> {
defaultness: Defaultness,
) -> PResult<'a, ItemInfo> {
let impl_span = self.token.span;
let mut err = self.expected_ident_found();
let mut err = self.expected_ident_found_err();
// Only try to recover if this is implementing a trait for a type
let mut impl_info = match self.parse_item_impl(attrs, defaultness) {
@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> {
/// Parses a field identifier. Specialized version of `parse_ident_common`
/// for better diagnostics and suggestions.
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
let (ident, is_raw) = self.ident_or_err()?;
let (ident, is_raw) = self.ident_or_err(true)?;
if !is_raw && ident.is_reserved() {
let snapshot = self.create_snapshot_for_diagnostic();
let err = if self.check_fn_front_matter(false, Case::Sensitive) {
@ -1776,7 +1776,7 @@ impl<'a> Parser<'a> {
Err(err) => {
err.cancel();
self.restore_snapshot(snapshot);
self.expected_ident_found()
self.expected_ident_found_err()
}
}
} else if self.eat_keyword(kw::Struct) {
@ -1792,11 +1792,11 @@ impl<'a> Parser<'a> {
Err(err) => {
err.cancel();
self.restore_snapshot(snapshot);
self.expected_ident_found()
self.expected_ident_found_err()
}
}
} else {
let mut err = self.expected_ident_found();
let mut err = self.expected_ident_found_err();
if self.eat_keyword_noexpect(kw::Let)
&& let removal_span = self.prev_token.span.until(self.token.span)
&& let Ok(ident) = self.parse_ident_common(false)

View file

@ -42,8 +42,7 @@ use thin_vec::ThinVec;
use tracing::debug;
use crate::errors::{
DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter,
NonStringAbiLiteral,
IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
};
bitflags::bitflags! {
@ -552,21 +551,11 @@ impl<'a> Parser<'a> {
self.parse_ident_common(true)
}
fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> {
self.token.ident().ok_or_else(|| match self.prev_token.kind {
TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything {
span: self.prev_token.span,
missing_comma: None,
}
.into_diagnostic(&self.sess.span_diagnostic),
_ => self.expected_ident_found(),
})
}
fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> {
let (ident, is_raw) = self.ident_or_err()?;
let (ident, is_raw) = self.ident_or_err(recover)?;
if !is_raw && ident.is_reserved() {
let mut err = self.expected_ident_found();
let mut err = self.expected_ident_found_err();
if recover {
err.emit();
} else {
@ -577,6 +566,21 @@ impl<'a> Parser<'a> {
Ok(ident)
}
fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> {
let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover));
let (ident, is_raw) = match result {
Ok(ident) => ident,
Err(err) => match err {
// we recovered!
Ok(ident) => ident,
Err(err) => return Err(err),
},
};
Ok((ident, is_raw))
}
/// Checks if the next token is `tok`, and returns `true` if so.
///
/// This method will automatically add `tok` to `expected_tokens` if `tok` is not

View file

@ -348,10 +348,6 @@ impl<'a> Parser<'a> {
lo = self.token.span;
}
if self.is_lit_bad_ident() {
return Err(self.expected_ident_found());
}
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
self.parse_pat_deref(expected)?
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
@ -395,7 +391,13 @@ impl<'a> Parser<'a> {
} else {
PatKind::Lit(const_expr)
}
} else if self.can_be_ident_pat() {
// Don't eagerly error on semantically invalid tokens when matching
// declarative macros, as the input to those doesn't have to be
// semantically valid. For attribute/derive proc macros this is not the
// case, so doing the recovery for them is fine.
} else if self.can_be_ident_pat()
|| (self.is_lit_bad_ident().is_some() && self.may_recover())
{
// Parse `ident @ pat`
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve.
@ -594,7 +596,7 @@ impl<'a> Parser<'a> {
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
if let token::Interpolated(nt) = &self.token.kind {
if let token::NtPat(_) = **nt {
self.expected_ident_found().emit();
self.expected_ident_found_err().emit();
}
}

View file

@ -1907,7 +1907,7 @@ impl CheckAttrVisitor<'_> {
match target {
Target::Fn => {
for attr in attrs {
if self.tcx.sess.is_proc_macro_attr(attr) {
if attr.is_proc_macro_attr() {
debug!("Is proc macro attr");
return true;
}

View file

@ -1,3 +1,4 @@
use rustc_ast::attr;
use rustc_ast::entry::EntryPointType;
use rustc_errors::error_code;
use rustc_hir::def::DefKind;
@ -37,7 +38,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
}
// If the user wants no main function at all, then stop here.
if tcx.sess.contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) {
if attr::contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) {
return None;
}
@ -57,9 +58,9 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
// An equivalent optimization was not applied to the duplicated code in test_harness.rs.
fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
if ctxt.tcx.sess.contains_name(attrs, sym::start) {
if attr::contains_name(attrs, sym::start) {
EntryPointType::Start
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
} else if attr::contains_name(attrs, sym::rustc_main) {
EntryPointType::RustcMainAttr
} else {
if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id())
@ -78,7 +79,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span)
attr::find_by_name(attrs, sym).map(|attr| attr.span)
}
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {

View file

@ -570,7 +570,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
ast::UseTreeKind::Glob => {
let kind = ImportKind::Glob {
is_prelude: self.r.tcx.sess.contains_name(&item.attrs, sym::prelude_import),
is_prelude: attr::contains_name(&item.attrs, sym::prelude_import),
max_vis: Cell::new(None),
id,
};
@ -685,7 +685,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
expansion.to_expn_id(),
item.span,
parent.no_implicit_prelude
|| self.r.tcx.sess.contains_name(&item.attrs, sym::no_implicit_prelude),
|| attr::contains_name(&item.attrs, sym::no_implicit_prelude),
);
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
@ -750,7 +750,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// If the structure is marked as non_exhaustive then lower the visibility
// to within the crate.
let mut ctor_vis = if vis.is_public()
&& self.r.tcx.sess.contains_name(&item.attrs, sym::non_exhaustive)
&& attr::contains_name(&item.attrs, sym::non_exhaustive)
{
ty::Visibility::Restricted(CRATE_DEF_ID)
} else {
@ -1168,12 +1168,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro) {
if attr::contains_name(&item.attrs, sym::proc_macro) {
return Some((MacroKind::Bang, item.ident, item.span));
} else if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro_attribute) {
} else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
return Some((MacroKind::Attr, item.ident, item.span));
} else if let Some(attr) = self.r.tcx.sess.find_by_name(&item.attrs, sym::proc_macro_derive)
{
} else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
if let Some(ident) = nested_meta.ident() {
return Some((MacroKind::Derive, ident, ident.span));
@ -1228,7 +1227,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
if macro_rules {
let ident = ident.normalize_to_macros_2_0();
self.r.macro_names.insert(ident);
let is_macro_export = self.r.tcx.sess.contains_name(&item.attrs, sym::macro_export);
let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
let vis = if is_macro_export {
ty::Visibility::Public
} else {
@ -1488,13 +1487,12 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.r.visibilities.insert(def_id, vis);
// If the variant is marked as non_exhaustive then lower the visibility to within the crate.
let ctor_vis = if vis.is_public()
&& self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive)
{
ty::Visibility::Restricted(CRATE_DEF_ID)
} else {
vis
};
let ctor_vis =
if vis.is_public() && attr::contains_name(&variant.attrs, sym::non_exhaustive) {
ty::Visibility::Restricted(CRATE_DEF_ID)
} else {
vis
};
// Define a constructor name in the value namespace.
if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) {

View file

@ -23,7 +23,7 @@ extern crate tracing;
use rustc_arena::{DroplessArena, TypedArena};
use rustc_ast::node_id::NodeMap;
use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID};
use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
@ -1190,7 +1190,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
ExpnId::root(),
krate.spans.inner_span,
tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude),
attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
&mut module_map,
);
let empty_module = arenas.new_module(
@ -1222,9 +1222,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.map(|(name, _)| (Ident::from_str(name), Default::default()))
.collect();
if !tcx.sess.contains_name(&krate.attrs, sym::no_core) {
if !attr::contains_name(&krate.attrs, sym::no_core) {
extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
if !tcx.sess.contains_name(&krate.attrs, sym::no_std) {
if !attr::contains_name(&krate.attrs, sym::no_std) {
extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
}
}

View file

@ -5,7 +5,7 @@ use crate::Namespace::*;
use crate::{BuiltinMacroState, Determinacy};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment};
use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId};
use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId};
use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
use rustc_data_structures::intern::Interned;
@ -113,7 +113,7 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
let mut registered_tools = RegisteredTools::default();
let krate = tcx.crate_for_resolver(()).borrow();
for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) {
for attr in attr::filter_by_name(&krate.attrs, sym::register_tool) {
for nested_meta in attr.meta_item_list().unwrap_or_default() {
match nested_meta.ident() {
Some(ident) => {
@ -703,7 +703,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
check_consistency(self, &path, path_span, kind, initial_res, res)
}
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
let mut suggestion = None;
let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
// try to suggest if it's not a macro, maybe a function

View file

@ -26,11 +26,13 @@ pub enum DocFragmentKind {
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct DocFragment {
pub span: Span,
/// The module this doc-comment came from.
///
/// This allows distinguishing between the original documentation and a pub re-export.
/// If it is `None`, the item was not re-exported.
pub parent_module: Option<DefId>,
/// The item this doc-comment came from.
/// Used to determine the scope in which doc links in this fragment are resolved.
/// Typically filled for reexport docs when they are merged into the docs of the
/// original reexported item.
/// If the id is not filled, which happens for the original reexported item, then
/// it has to be taken from somewhere else during doc link resolution.
pub item_id: Option<DefId>,
pub doc: Symbol,
pub kind: DocFragmentKind,
pub indent: usize,
@ -186,7 +188,7 @@ pub fn attrs_to_doc_fragments<'a>(
) -> (Vec<DocFragment>, ast::AttrVec) {
let mut doc_fragments = Vec::new();
let mut other_attrs = ast::AttrVec::new();
for (attr, parent_module) in attrs {
for (attr, item_id) in attrs {
if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
let doc = beautify_doc_string(doc_str, comment_kind);
let kind = if attr.is_doc_comment() {
@ -194,7 +196,7 @@ pub fn attrs_to_doc_fragments<'a>(
} else {
DocFragmentKind::RawDoc
};
let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
let fragment = DocFragment { span: attr.span, doc, kind, item_id, indent: 0 };
doc_fragments.push(fragment);
} else if !doc_only {
other_attrs.push(attr.clone());
@ -216,7 +218,7 @@ pub fn prepare_to_doc_link_resolution(
) -> FxHashMap<Option<DefId>, String> {
let mut res = FxHashMap::default();
for fragment in doc_fragments {
let out_str = res.entry(fragment.parent_module).or_default();
let out_str = res.entry(fragment.item_id).or_default();
add_doc_fragment(out_str, fragment);
}
res

View file

@ -5,7 +5,7 @@ use crate::errors::{
InvalidCharacterInCrateName,
};
use crate::Session;
use rustc_ast as ast;
use rustc_ast::{self as ast, attr};
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use std::path::{Path, PathBuf};
@ -56,7 +56,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol {
// the command line over one found in the #[crate_name] attribute. If we
// find both we ensure that they're the same later on as well.
let attr_crate_name =
sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
if let Some(ref s) = sess.opts.crate_name {
let s = Symbol::intern(s);

View file

@ -30,7 +30,7 @@ use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
use rustc_span::edition::Edition;
use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_span::{SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
use rustc_target::spec::{
@ -1003,40 +1003,6 @@ impl Session {
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
}
pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
.any(|kind| attr.has_name(*kind))
}
pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool {
attrs.iter().any(|item| item.has_name(name))
}
pub fn find_by_name<'a>(
&'a self,
attrs: &'a [Attribute],
name: Symbol,
) -> Option<&'a Attribute> {
attrs.iter().find(|attr| attr.has_name(name))
}
pub fn filter_by_name<'a>(
&'a self,
attrs: &'a [Attribute],
name: Symbol,
) -> impl Iterator<Item = &'a Attribute> {
attrs.iter().filter(move |attr| attr.has_name(name))
}
pub fn first_attr_value_str_by_name(
&self,
attrs: &[Attribute],
name: Symbol,
) -> Option<Symbol> {
attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str())
}
pub fn diagnostic_width(&self) -> usize {
let default_column_width = 140;
if let Some(width) = self.opts.diagnostic_width {

View file

@ -18,3 +18,4 @@ tracing = "0.1"
sha1 = "0.10.0"
sha2 = "0.10.1"
md5 = { package = "md-5", version = "0.10.0" }
indexmap = { version = "1.9.1" }

View file

@ -1,13 +1,17 @@
use crate::{HashStableContext, Symbol};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_data_structures::unhash::Unhasher;
use rustc_data_structures::AtomicRef;
use rustc_index::vec::Idx;
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::borrow::Borrow;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::hash::{BuildHasherDefault, Hash, Hasher};
pub type StableCrateIdMap =
indexmap::IndexMap<StableCrateId, CrateNum, BuildHasherDefault<Unhasher>>;
rustc_index::newtype_index! {
#[custom_encodable]

View file

@ -795,6 +795,18 @@ impl Span {
})
}
/// Splits a span into two composite spans around a certain position.
pub fn split_at(self, pos: u32) -> (Span, Span) {
let len = self.hi().0 - self.lo().0;
debug_assert!(pos <= len);
let split_pos = BytePos(self.lo().0 + pos);
(
Span::new(self.lo(), split_pos, self.ctxt(), self.parent()),
Span::new(split_pos, self.hi(), self.ctxt(), self.parent()),
)
}
/// Returns a `Span` that would enclose both `self` and `end`.
///
/// Note that this can also be used to extend the span "backwards":

View file

@ -1044,6 +1044,7 @@ symbols! {
optin_builtin_traits,
option,
option_env,
option_payload_ptr,
options,
or,
or_patterns,

View file

@ -2,7 +2,8 @@
#[cfg(doc)]
use super::trait_goals::structural_traits::*;
use super::EvalCtxt;
use super::{EvalCtxt, SolverMode};
use crate::traits::coherence;
use itertools::Itertools;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution;
@ -87,6 +88,8 @@ pub(super) enum CandidateSource {
pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
fn self_ty(self) -> Ty<'tcx>;
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
@ -244,15 +247,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.assemble_object_bound_candidates(goal, &mut candidates);
self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
candidates
}
/// If the self type of a goal is a projection, computing the relevant candidates is difficult.
///
/// To deal with this, we first try to normalize the self type and add the candidates for the normalized
/// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in
/// this case as projections as self types add
// FIXME complete the unfinished sentence above
/// self type to the list of candidates in case that succeeds. We also have to consider candidates with the
/// projection as a self type as well
fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
@ -468,14 +472,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
) {
match self.solver_mode() {
SolverMode::Normal => return,
SolverMode::Coherence => {
let trait_ref = goal.predicate.trait_ref(self.tcx());
match coherence::trait_ref_is_knowable(self.tcx(), trait_ref) {
Ok(()) => {}
Err(_) => match self
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
{
Ok(result) => candidates
.push(Candidate { source: CandidateSource::BuiltinImpl, result }),
// FIXME: This will be reachable at some point if we're in
// `assemble_candidates_after_normalizing_self_ty` and we get a
// universe error. We'll deal with it at this point.
Err(NoSolution) => bug!("coherence candidate resulted in NoSolution"),
},
}
}
}
}
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_candidates_and_discard_reservation_impls(
pub(super) fn merge_candidates(
&mut self,
mut candidates: Vec<Candidate<'tcx>>,
) -> QueryResult<'tcx> {
match candidates.len() {
0 => return Err(NoSolution),
1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
1 => return Ok(candidates.pop().unwrap().result),
_ => {}
}
@ -483,10 +513,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let mut i = 0;
'outer: while i < candidates.len() {
for j in (0..candidates.len()).filter(|&j| i != j) {
if self.trait_candidate_should_be_dropped_in_favor_of(
&candidates[i],
&candidates[j],
) {
if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
{
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
candidates.swap_remove(i);
continue 'outer;
@ -511,11 +539,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
// FIXME: What if there are >1 candidates left with the same response, and one is a reservation impl?
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
Ok(candidates.pop().unwrap().result)
}
fn trait_candidate_should_be_dropped_in_favor_of(
fn candidate_should_be_dropped_in_favor_of(
&self,
candidate: &Candidate<'tcx>,
other: &Candidate<'tcx>,
@ -528,20 +555,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| (CandidateSource::BuiltinImpl, _) => false,
}
}
fn discard_reservation_impl(&mut self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
if let CandidateSource::Impl(def_id) = candidate.source {
if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
debug!("Selected reservation impl");
// We assemble all candidates inside of a probe so by
// making a new canonical response here our result will
// have no constraints.
candidate.result = self
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
.unwrap();
}
}
candidate
}
}

View file

@ -17,6 +17,7 @@ use rustc_span::DUMMY_SP;
use std::ops::ControlFlow;
use super::search_graph::{self, OverflowHandler};
use super::SolverMode;
use super::{search_graph::SearchGraph, Goal};
pub struct EvalCtxt<'a, 'tcx> {
@ -78,7 +79,9 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
) -> Result<(bool, Certainty), NoSolution> {
let mut search_graph = search_graph::SearchGraph::new(self.tcx);
let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
let mut ecx = EvalCtxt {
search_graph: &mut search_graph,
@ -101,6 +104,10 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
}
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
pub(super) fn solver_mode(&self) -> SolverMode {
self.search_graph.solver_mode()
}
/// The entry point of the solver.
///
/// This function deals with (coinductive) cycles, overflow, and caching
@ -120,8 +127,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
//
// The actual solver logic happens in `ecx.compute_goal`.
search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
let (ref infcx, goal, var_values) =
tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
let intercrate = match search_graph.solver_mode() {
SolverMode::Normal => false,
SolverMode::Coherence => true,
};
let (ref infcx, goal, var_values) = tcx
.infer_ctxt()
.intercrate(intercrate)
.build_with_canonical(DUMMY_SP, &canonical_goal);
let mut ecx = EvalCtxt {
infcx,
var_values,

View file

@ -9,10 +9,6 @@
//! FIXME(@lcnr): Write that section. If you read this before then ask me
//! about it on zulip.
// FIXME: Instead of using `infcx.canonicalize_query` we have to add a new routine which
// preserves universes and creates a unique var (in the highest universe) for each
// appearance of a region.
// FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
use rustc_hir::def_id::DefId;
@ -41,6 +37,19 @@ mod trait_goals;
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
pub use fulfill::FulfillmentCtxt;
#[derive(Debug, Clone, Copy)]
enum SolverMode {
/// Ordinary trait solving, using everywhere except for coherence.
Normal,
/// Trait solving during coherence. There are a few notable differences
/// between coherence and ordinary trait solving.
///
/// Most importantly, trait solving during coherence must not be incomplete,
/// i.e. return `Err(NoSolution)` for goals for which a solution exists.
/// This means that we must not make any guesses or arbitrary choices.
Coherence,
}
trait CanonicalResponseExt {
fn has_no_inference_or_external_constraints(&self) -> bool;
}
@ -255,7 +264,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return Err(NoSolution);
}
// FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with
// FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with
// a subset of the constraints that all the other responses have.
let one = candidates[0];
if candidates[1..].iter().all(|resp| resp == &one) {

View file

@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// projection cache in the solver.
if self.term_is_fully_unconstrained(goal) {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_candidates_and_discard_reservation_impls(candidates)
self.merge_candidates(candidates)
} else {
let predicate = goal.predicate;
let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term);
@ -56,6 +56,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
self.self_ty()
}
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
self.projection_ty.trait_ref(tcx)
}
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
self.with_self_ty(tcx, self_ty)
}

View file

@ -1,8 +1,9 @@
mod cache;
mod overflow;
pub(super) use overflow::OverflowHandler;
use self::cache::ProvisionalEntry;
pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
use cache::ProvisionalCache;
use overflow::OverflowData;
use rustc_index::vec::IndexVec;
@ -11,6 +12,8 @@ use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryRes
use rustc_middle::ty::TyCtxt;
use std::{collections::hash_map::Entry, mem};
use super::SolverMode;
rustc_index::newtype_index! {
pub struct StackDepth {}
}
@ -21,6 +24,7 @@ struct StackElem<'tcx> {
}
pub(super) struct SearchGraph<'tcx> {
mode: SolverMode,
/// The stack of goals currently being computed.
///
/// An element is *deeper* in the stack if its index is *lower*.
@ -30,14 +34,19 @@ pub(super) struct SearchGraph<'tcx> {
}
impl<'tcx> SearchGraph<'tcx> {
pub(super) fn new(tcx: TyCtxt<'tcx>) -> SearchGraph<'tcx> {
pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
Self {
mode,
stack: Default::default(),
overflow_data: OverflowData::new(tcx),
provisional_cache: ProvisionalCache::empty(),
}
}
pub(super) fn solver_mode(&self) -> SolverMode {
self.mode
}
pub(super) fn is_empty(&self) -> bool {
self.stack.is_empty() && self.provisional_cache.is_empty()
}
@ -245,7 +254,8 @@ impl<'tcx> SearchGraph<'tcx> {
// dependencies, our non-root goal may no longer appear as child of the root goal.
//
// See https://github.com/rust-lang/rust/pull/108071 for some additional context.
let should_cache_globally = !self.overflow_data.did_overflow() || self.stack.is_empty();
let should_cache_globally = matches!(self.solver_mode(), SolverMode::Normal)
&& (!self.overflow_data.did_overflow() || self.stack.is_empty());
if should_cache_globally {
tcx.new_solver_evaluation_cache.insert(
current_goal.goal,

View file

@ -2,7 +2,7 @@
use std::iter;
use super::{assembly, EvalCtxt};
use super::{assembly, EvalCtxt, SolverMode};
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
use rustc_infer::traits::query::NoSolution;
@ -20,6 +20,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
self.self_ty()
}
fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
self.trait_ref
}
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
self.with_self_ty(tcx, self_ty)
}
@ -43,6 +47,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
return Err(NoSolution);
}
let impl_polarity = tcx.impl_polarity(impl_def_id);
// An upper bound of the certainty of this goal, used to lower the certainty
// of reservation impl to ambiguous during coherence.
let maximal_certainty = match impl_polarity {
ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => {
match impl_polarity == goal.predicate.polarity {
true => Certainty::Yes,
false => return Err(NoSolution),
}
}
ty::ImplPolarity::Reservation => match ecx.solver_mode() {
SolverMode::Normal => return Err(NoSolution),
SolverMode::Coherence => Certainty::AMBIGUOUS,
},
};
ecx.probe(|ecx| {
let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
@ -55,7 +75,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
.into_iter()
.map(|pred| goal.with(tcx, pred));
ecx.add_goals(where_clause_bounds);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
})
}
@ -547,6 +568,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
goal: Goal<'tcx, TraitPredicate<'tcx>>,
) -> QueryResult<'tcx> {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_candidates_and_discard_reservation_impls(candidates)
self.merge_candidates(candidates)
}
}

View file

@ -95,8 +95,11 @@ pub fn overlapping_impls(
return None;
}
let infcx =
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
let infcx = tcx
.infer_ctxt()
.with_opaque_type_inference(DefiningAnchor::Bubble)
.intercrate(true)
.build();
let selcx = &mut SelectionContext::new(&infcx);
let overlaps =
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
@ -107,8 +110,11 @@ pub fn overlapping_impls(
// In the case where we detect an error, run the check again, but
// this time tracking intercrate ambiguity causes for better
// diagnostics. (These take time and can lead to false errors.)
let infcx =
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
let infcx = tcx
.infer_ctxt()
.with_opaque_type_inference(DefiningAnchor::Bubble)
.intercrate(true)
.build();
let selcx = &mut SelectionContext::new(&infcx);
selcx.enable_tracking_intercrate_ambiguity_causes();
Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())

View file

@ -212,7 +212,7 @@ pub trait TypeErrCtxtExt<'tcx> {
fn extract_callable_info(
&self,
hir_id: HirId,
body_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
found: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
@ -909,9 +909,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_pred.self_ty(),
);
let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(
body_hir_id,
obligation.cause.body_id,
obligation.param_env,
self_ty,
) else { return false; };
@ -1113,10 +1112,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
/// Extracts information about a callable type for diagnostics. This is a
/// heuristic -- it doesn't necessarily mean that a type is always callable,
/// because the callable type must also be well-formed to be called.
// FIXME(vincenzopalazzo): move the HirId to a LocalDefId
fn extract_callable_info(
&self,
hir_id: HirId,
body_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
found: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
@ -1168,7 +1166,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
})
}
ty::Param(param) => {
let generics = self.tcx.generics_of(hir_id.owner.to_def_id());
let generics = self.tcx.generics_of(body_id);
let name = if generics.count() > param.index as usize
&& let def = generics.param_at(param.index as usize, self.tcx)
&& matches!(def.kind, ty::GenericParamDefKind::Type { .. })

View file

@ -4,7 +4,7 @@
pub mod auto_trait;
mod chalk_fulfill;
mod coherence;
pub(crate) mod coherence;
pub mod const_evaluatable;
mod engine;
pub mod error_reporting;

View file

@ -539,7 +539,7 @@ fn make_thin_self_ptr<'tcx>(
// get a built-in pointer type
let mut fat_pointer_layout = layout;
'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
&& !fat_pointer_layout.ty.is_region_ptr()
&& !fat_pointer_layout.ty.is_ref()
{
for i in 0..fat_pointer_layout.fields.count() {
let field_layout = fat_pointer_layout.field(cx, i);

View file

@ -254,13 +254,16 @@ fn associated_type_for_impl_trait_in_trait(
tcx: TyCtxt<'_>,
opaque_ty_def_id: LocalDefId,
) -> LocalDefId {
let fn_def_id = tcx.impl_trait_in_trait_parent_fn(opaque_ty_def_id.to_def_id());
let trait_def_id = tcx.parent(fn_def_id);
let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) =
tcx.hir().expect_item(opaque_ty_def_id).expect_opaque_ty().origin
else {
bug!("expected opaque for {opaque_ty_def_id:?}");
};
let trait_def_id = tcx.local_parent(fn_def_id);
assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
let span = tcx.def_span(opaque_ty_def_id);
let trait_assoc_ty =
tcx.at(span).create_def(trait_def_id.expect_local(), DefPathData::ImplTraitAssocTy);
let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, DefPathData::ImplTraitAssocTy);
let local_def_id = trait_assoc_ty.def_id();
let def_id = local_def_id.to_def_id();
@ -282,7 +285,7 @@ fn associated_type_for_impl_trait_in_trait(
container: ty::TraitContainer,
fn_has_self_parameter: false,
opt_rpitit_info: Some(ImplTraitInTraitData::Trait {
fn_def_id,
fn_def_id: fn_def_id.to_def_id(),
opaque_def_id: opaque_ty_def_id.to_def_id(),
}),
});
@ -324,7 +327,7 @@ fn associated_type_for_impl_trait_in_trait(
params.iter().map(|param| (param.def_id, param.index)).collect();
ty::Generics {
parent: Some(trait_def_id),
parent: Some(trait_def_id.to_def_id()),
parent_count,
params,
param_def_id_to_index,
@ -335,7 +338,7 @@ fn associated_type_for_impl_trait_in_trait(
// There are no predicates for the synthesized associated type.
trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
parent: Some(trait_def_id),
parent: Some(trait_def_id.to_def_id()),
predicates: &[],
});
@ -356,7 +359,6 @@ fn associated_type_for_impl_trait_in_impl(
impl_fn_def_id: LocalDefId,
) -> LocalDefId {
let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
let impl_def_id = impl_local_def_id.to_def_id();
// FIXME fix the span, we probably want the def_id of the return type of the function
let span = tcx.def_span(impl_fn_def_id);
@ -384,10 +386,6 @@ fn associated_type_for_impl_trait_in_impl(
opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
});
// Copy param_env of the containing function. The synthesized associated type doesn't have
// extra predicates to assume.
impl_assoc_ty.param_env(tcx.param_env(impl_fn_def_id));
// Copy visility of the containing function.
impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id));
@ -402,7 +400,7 @@ fn associated_type_for_impl_trait_in_impl(
let trait_assoc_parent_count = trait_assoc_generics.parent_count;
let mut params = trait_assoc_generics.params.clone();
let parent_generics = tcx.generics_of(impl_def_id);
let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
let parent_count = parent_generics.parent_count + parent_generics.params.len();
for param in &mut params {
@ -413,7 +411,7 @@ fn associated_type_for_impl_trait_in_impl(
params.iter().map(|param| (param.def_id, param.index)).collect();
ty::Generics {
parent: Some(impl_def_id),
parent: Some(impl_local_def_id.to_def_id()),
parent_count,
params,
param_def_id_to_index,
@ -424,7 +422,7 @@ fn associated_type_for_impl_trait_in_impl(
// There are no predicates for the synthesized associated type.
impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
parent: Some(impl_def_id),
parent: Some(impl_local_def_id.to_def_id()),
predicates: &[],
});

Some files were not shown because too many files have changed in this diff Show more