Auto merge of #109503 - matthiaskrgr:rollup-cnp7kdd, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #108954 (rustdoc: handle generics better when matching notable traits) - #109203 (refactor/feat: refactor identifier parsing a bit) - #109213 (Eagerly intern and check CrateNum/StableCrateId collisions) - #109358 (rustc: Remove unused `Session` argument from some attribute functions) - #109359 (Update stdarch) - #109378 (Remove Ty::is_region_ptr) - #109423 (Use region-erased self type during IAT selection) - #109447 (new solver cleanup + implement coherence) - #109501 (make link clickable) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
84dd6dfd9d
106 changed files with 909 additions and 592 deletions
|
@ -5294,6 +5294,7 @@ name = "rustc_span"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"indexmap",
|
||||||
"md-5",
|
"md-5",
|
||||||
"rustc_arena",
|
"rustc_arena",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
|
|
|
@ -180,6 +180,12 @@ impl Attribute {
|
||||||
self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
|
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.
|
/// Extracts the MetaItem from inside this Attribute.
|
||||||
pub fn meta(&self) -> Option<MetaItem> {
|
pub fn meta(&self) -> Option<MetaItem> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
|
@ -627,6 +633,22 @@ pub fn mk_attr_name_value_str(
|
||||||
mk_attr(g, style, path, args, span)
|
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 {
|
pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
|
||||||
items.iter().any(|item| item.has_name(name))
|
items.iter().any(|item| item.has_name(name))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2185,7 +2185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
def_id: self.local_def_id(param.id),
|
def_id: self.local_def_id(param.id),
|
||||||
name,
|
name,
|
||||||
span: self.lower_span(param.span()),
|
span: self.lower_span(param.span()),
|
||||||
pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle),
|
pure_wrt_drop: attr::contains_name(¶m.attrs, sym::may_dangle),
|
||||||
kind,
|
kind,
|
||||||
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
||||||
source,
|
source,
|
||||||
|
|
|
@ -799,11 +799,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_item(&mut self, item: &'a Item) {
|
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;
|
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);
|
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).
|
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
||||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
|
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);
|
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) {
|
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);
|
self.check_nomangle_item_asciionly(item.ident, item.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
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_ast::{PatKind, RangeEnd};
|
||||||
use rustc_errors::{Applicability, StashKey};
|
use rustc_errors::{Applicability, StashKey};
|
||||||
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
|
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
|
||||||
|
@ -232,7 +232,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ItemKind::Fn(..) => {
|
ast::ItemKind::Fn(..) => {
|
||||||
if self.sess.contains_name(&i.attrs, sym::start) {
|
if attr::contains_name(&i.attrs, sym::start) {
|
||||||
gate_feature_post!(
|
gate_feature_post!(
|
||||||
&self,
|
&self,
|
||||||
start,
|
start,
|
||||||
|
@ -245,7 +245,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ItemKind::Struct(..) => {
|
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) {
|
for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
|
||||||
if item.has_name(sym::simd) {
|
if item.has_name(sym::simd) {
|
||||||
gate_feature_post!(
|
gate_feature_post!(
|
||||||
|
@ -306,7 +306,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
|
fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
|
||||||
match i.kind {
|
match i.kind {
|
||||||
ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
|
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 =
|
let links_to_llvm =
|
||||||
link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
|
link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
|
||||||
if links_to_llvm {
|
if links_to_llvm {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Parsing and validation of builtin attributes
|
//! 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::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
|
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
|
||||||
|
@ -556,8 +556,8 @@ where
|
||||||
(stab, const_stab, body_stab)
|
(stab, const_stab, body_stab)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
|
||||||
sess.first_attr_value_str_by_name(attrs, sym::crate_name)
|
attr::first_attr_value_str_by_name(attrs, sym::crate_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -1177,7 +1177,7 @@ fn allow_unstable<'a>(
|
||||||
attrs: &'a [Attribute],
|
attrs: &'a [Attribute],
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
) -> impl Iterator<Item = Symbol> + 'a {
|
) -> impl Iterator<Item = Symbol> + 'a {
|
||||||
let attrs = sess.filter_by_name(attrs, symbol);
|
let attrs = attr::filter_by_name(attrs, symbol);
|
||||||
let list = attrs
|
let list = attrs
|
||||||
.filter_map(move |attr| {
|
.filter_map(move |attr| {
|
||||||
attr.meta_item_list().or_else(|| {
|
attr.meta_item_list().or_else(|| {
|
||||||
|
|
|
@ -120,9 +120,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
&& !self.upvars.is_empty()
|
&& !self.upvars.is_empty()
|
||||||
{
|
{
|
||||||
item_msg = access_place_desc;
|
item_msg = access_place_desc;
|
||||||
debug_assert!(
|
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
|
||||||
self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
|
|
||||||
);
|
|
||||||
debug_assert!(is_closure_or_generator(
|
debug_assert!(is_closure_or_generator(
|
||||||
Place::ty_from(
|
Place::ty_from(
|
||||||
the_place_err.local,
|
the_place_err.local,
|
||||||
|
@ -470,11 +468,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
let local_decl = &self.body.local_decls[local];
|
let local_decl = &self.body.local_decls[local];
|
||||||
|
|
||||||
let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() {
|
let (pointer_sigil, pointer_desc) =
|
||||||
("&", "reference")
|
if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
|
||||||
} else {
|
|
||||||
("*const", "pointer")
|
|
||||||
};
|
|
||||||
|
|
||||||
match self.local_names[local] {
|
match self.local_names[local] {
|
||||||
Some(name) if !local_decl.from_compiler_desugaring() => {
|
Some(name) if !local_decl.from_compiler_desugaring() => {
|
||||||
|
@ -1258,7 +1253,7 @@ fn suggest_ampmut<'tcx>(
|
||||||
(
|
(
|
||||||
suggestability,
|
suggestability,
|
||||||
highlight_span,
|
highlight_span,
|
||||||
if local_decl.ty.is_region_ptr() {
|
if local_decl.ty.is_ref() {
|
||||||
format!("&mut {}", ty_mut.ty)
|
format!("&mut {}", ty_mut.ty)
|
||||||
} else {
|
} else {
|
||||||
format!("*mut {}", ty_mut.ty)
|
format!("*mut {}", ty_mut.ty)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::deriving::generic::ty::*;
|
use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
use rustc_ast as ast;
|
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_errors::Applicability;
|
||||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
@ -106,7 +106,7 @@ fn extract_default_variant<'a>(
|
||||||
let default_variants: SmallVec<[_; 1]> = enum_def
|
let default_variants: SmallVec<[_; 1]> = enum_def
|
||||||
.variants
|
.variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default))
|
.filter(|variant| attr::contains_name(&variant.attrs, kw::Default))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let variant = match default_variants.as_slice() {
|
let variant = match default_variants.as_slice() {
|
||||||
|
@ -116,7 +116,7 @@ fn extract_default_variant<'a>(
|
||||||
.variants
|
.variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|variant| matches!(variant.data, VariantData::Unit(..)))
|
.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");
|
let mut diag = cx.struct_span_err(trait_span, "no default declared");
|
||||||
diag.help("make a unit variant default by placing `#[default]` above it");
|
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 {
|
if v.span == variant.span {
|
||||||
None
|
None
|
||||||
} else {
|
} 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();
|
.collect();
|
||||||
|
@ -174,7 +174,7 @@ fn extract_default_variant<'a>(
|
||||||
return Err(());
|
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")
|
cx.struct_span_err(variant.ident.span, "default variant must be exhaustive")
|
||||||
.span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
|
.span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
|
||||||
.help("consider a manual implementation of `Default`")
|
.help("consider a manual implementation of `Default`")
|
||||||
|
@ -191,7 +191,7 @@ fn validate_default_attribute(
|
||||||
default_variant: &rustc_ast::Variant,
|
default_variant: &rustc_ast::Variant,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let attrs: SmallVec<[_; 1]> =
|
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() {
|
let attr = match attrs.as_slice() {
|
||||||
[attr] => attr,
|
[attr] => attr,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::visit::{self, Visitor};
|
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_ast_pretty::pprust;
|
||||||
use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
|
use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
|
||||||
use rustc_expand::expand::{AstFragment, ExpansionConfig};
|
use rustc_expand::expand::{AstFragment, ExpansionConfig};
|
||||||
|
@ -34,7 +34,6 @@ enum ProcMacro {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CollectProcMacros<'a> {
|
struct CollectProcMacros<'a> {
|
||||||
sess: &'a Session,
|
|
||||||
macros: Vec<ProcMacro>,
|
macros: Vec<ProcMacro>,
|
||||||
in_root: bool,
|
in_root: bool,
|
||||||
handler: &'a rustc_errors::Handler,
|
handler: &'a rustc_errors::Handler,
|
||||||
|
@ -56,7 +55,6 @@ pub fn inject(
|
||||||
let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
|
let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
|
||||||
|
|
||||||
let mut collect = CollectProcMacros {
|
let mut collect = CollectProcMacros {
|
||||||
sess,
|
|
||||||
macros: Vec::new(),
|
macros: Vec::new(),
|
||||||
in_root: true,
|
in_root: true,
|
||||||
handler,
|
handler,
|
||||||
|
@ -160,7 +158,7 @@ impl<'a> CollectProcMacros<'a> {
|
||||||
impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
||||||
fn visit_item(&mut self, item: &'a ast::Item) {
|
fn visit_item(&mut self, item: &'a ast::Item) {
|
||||||
if let ast::ItemKind::MacroDef(..) = item.kind {
|
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 =
|
let msg =
|
||||||
"cannot export macro_rules! macros from a `proc-macro` crate type currently";
|
"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);
|
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;
|
let mut found_attr: Option<&'a ast::Attribute> = None;
|
||||||
|
|
||||||
for attr in &item.attrs {
|
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 {
|
if let Some(prev_attr) = found_attr {
|
||||||
let prev_item = prev_attr.get_normal_item();
|
let prev_item = prev_attr.get_normal_item();
|
||||||
let item = attr.get_normal_item();
|
let item = attr.get_normal_item();
|
||||||
|
|
|
@ -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::base::{ExtCtxt, ResolverExpand};
|
||||||
use rustc_expand::expand::ExpansionConfig;
|
use rustc_expand::expand::ExpansionConfig;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
@ -16,10 +16,10 @@ pub fn inject(
|
||||||
let edition = sess.parse_sess.edition;
|
let edition = sess.parse_sess.edition;
|
||||||
|
|
||||||
// the first name in this list is the crate name of the crate with the prelude
|
// 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;
|
return krate;
|
||||||
} else if sess.contains_name(&krate.attrs, sym::no_std) {
|
} else if attr::contains_name(&krate.attrs, sym::no_std) {
|
||||||
if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
|
if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
|
||||||
&[sym::core]
|
&[sym::core]
|
||||||
} else {
|
} else {
|
||||||
&[sym::core, sym::compiler_builtins]
|
&[sym::core, sym::compiler_builtins]
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
/// The expansion from a test function to the appropriate test struct for libtest
|
/// 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.
|
/// 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 crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
|
||||||
use rustc_ast as ast;
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
|
use rustc_ast::{self as ast, attr};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_expand::base::*;
|
use rustc_expand::base::*;
|
||||||
use rustc_session::Session;
|
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
use rustc_span::{FileNameDisplayPreference, Span};
|
use rustc_span::{FileNameDisplayPreference, Span};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -291,14 +290,11 @@ pub fn expand_test_or_bench(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// ignore: true | false
|
// ignore: true | false
|
||||||
field(
|
field("ignore", cx.expr_bool(sp, should_ignore(&item)),),
|
||||||
"ignore",
|
|
||||||
cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
|
|
||||||
),
|
|
||||||
// ignore_message: Some("...") | None
|
// ignore_message: Some("...") | None
|
||||||
field(
|
field(
|
||||||
"ignore_message",
|
"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))
|
cx.expr_some(sp, cx.expr_str(sp, msg))
|
||||||
} else {
|
} else {
|
||||||
cx.expr_none(sp)
|
cx.expr_none(sp)
|
||||||
|
@ -425,12 +421,12 @@ enum ShouldPanic {
|
||||||
Yes(Option<Symbol>),
|
Yes(Option<Symbol>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_ignore(sess: &Session, i: &ast::Item) -> bool {
|
fn should_ignore(i: &ast::Item) -> bool {
|
||||||
sess.contains_name(&i.attrs, sym::ignore)
|
attr::contains_name(&i.attrs, sym::ignore)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> {
|
fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {
|
||||||
match cx.sess.find_by_name(&i.attrs, sym::ignore) {
|
match attr::find_by_name(&i.attrs, sym::ignore) {
|
||||||
Some(attr) => {
|
Some(attr) => {
|
||||||
match attr.meta_item_list() {
|
match attr.meta_item_list() {
|
||||||
// Handle #[ignore(bar = "foo")]
|
// 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 {
|
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) => {
|
Some(attr) => {
|
||||||
let sd = &cx.sess.parse_sess.span_diagnostic;
|
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 {
|
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;
|
let sd = &cx.sess.parse_sess.span_diagnostic;
|
||||||
match &i.kind {
|
match &i.kind {
|
||||||
ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
|
ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
|
||||||
|
|
|
@ -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
|
// unconditional, so that the attribute is still marked as used in
|
||||||
// non-test builds.
|
// non-test builds.
|
||||||
let reexport_test_harness_main =
|
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
|
// Do this here so that the test_runner crate attribute gets marked as used
|
||||||
// even in non-test builds
|
// 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 {
|
if sess.opts.test {
|
||||||
let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
|
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]> {
|
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
|
||||||
let mut item = i.into_inner();
|
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");
|
debug!("this is a test item");
|
||||||
|
|
||||||
let test = Test { span: item.span, ident: item.ident, name };
|
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
|
// Beware, this is duplicated in librustc_passes/entry.rs (with
|
||||||
// `rustc_hir::Item`), so make sure to keep them in sync.
|
// `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 {
|
match item.kind {
|
||||||
ast::ItemKind::Fn(..) => {
|
ast::ItemKind::Fn(..) => {
|
||||||
if sess.contains_name(&item.attrs, sym::start) {
|
if attr::contains_name(&item.attrs, sym::start) {
|
||||||
EntryPointType::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
|
EntryPointType::RustcMainAttr
|
||||||
} else if item.ident.name == sym::main {
|
} else if item.ident.name == sym::main {
|
||||||
if depth == 0 {
|
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
|
// 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
|
// clash with the one we're going to add, but mark it as
|
||||||
// #[allow(dead_code)] to avoid printing warnings.
|
// #[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 => {
|
EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
|
||||||
item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
|
item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
|
||||||
let allow_dead_code = attr::mk_attr_nested_word(
|
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> {
|
fn get_test_name(i: &ast::Item) -> Option<Symbol> {
|
||||||
sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
|
attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_test_runner(
|
fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
|
||||||
sess: &Session,
|
let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
|
||||||
sd: &rustc_errors::Handler,
|
|
||||||
krate: &ast::Crate,
|
|
||||||
) -> Option<ast::Path> {
|
|
||||||
let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?;
|
|
||||||
let meta_list = test_attr.meta_item_list()?;
|
let meta_list = test_attr.meta_item_list()?;
|
||||||
let span = test_attr.span;
|
let span = test_attr.span;
|
||||||
match &*meta_list {
|
match &*meta_list {
|
||||||
|
|
|
@ -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_expand::base::{Annotatable, ExtCtxt};
|
||||||
use rustc_feature::AttributeTemplate;
|
use rustc_feature::AttributeTemplate;
|
||||||
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
|
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
|
||||||
|
@ -36,7 +36,7 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name:
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(attrs) = attrs {
|
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(
|
ecx.parse_sess().buffer_lint(
|
||||||
DUPLICATE_MACRO_ATTRIBUTES,
|
DUPLICATE_MACRO_ATTRIBUTES,
|
||||||
attr.span,
|
attr.span,
|
||||||
|
|
|
@ -48,9 +48,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
|
||||||
) -> (Pointer, Value) {
|
) -> (Pointer, Value) {
|
||||||
let (ptr, vtable) = 'block: {
|
let (ptr, vtable) = 'block: {
|
||||||
if let Abi::Scalar(_) = arg.layout().abi {
|
if let Abi::Scalar(_) = arg.layout().abi {
|
||||||
'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr()
|
'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
|
||||||
&& !arg.layout().ty.is_region_ptr()
|
|
||||||
{
|
|
||||||
for i in 0..arg.layout().fields.count() {
|
for i in 0..arg.layout().fields.count() {
|
||||||
let field = arg.value_field(fx, mir::Field::new(i));
|
let field = arg.value_field(fx, mir::Field::new(i));
|
||||||
if !field.layout().is_zst() {
|
if !field.layout().is_zst() {
|
||||||
|
|
|
@ -5,12 +5,12 @@ use crate::llvm;
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
use crate::common::CodegenCx;
|
use crate::common::CodegenCx;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
use rustc_ast::attr;
|
||||||
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
|
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
use rustc_hir::def_id::LOCAL_CRATE;
|
use rustc_hir::def_id::LOCAL_CRATE;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_session::config::{CrateType, DebugInfo};
|
use rustc_session::config::{CrateType, DebugInfo};
|
||||||
|
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::DebuggerVisualizerType;
|
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 {
|
pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
|
||||||
let omit_gdb_pretty_printer_section =
|
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
|
// 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
|
// ODR violations at link time, this section will not be emitted for rlibs since
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
||||||
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
||||||
};
|
};
|
||||||
use jobserver::{Acquired, Client};
|
use jobserver::{Acquired, Client};
|
||||||
|
use rustc_ast::attr;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::memmap::Mmap;
|
use rustc_data_structures::memmap::Mmap;
|
||||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||||
|
@ -447,8 +448,8 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
||||||
let sess = tcx.sess;
|
let sess = tcx.sess;
|
||||||
|
|
||||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||||
let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins);
|
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||||
let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins);
|
let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins);
|
||||||
|
|
||||||
let crate_info = CrateInfo::new(tcx, target_cpu);
|
let crate_info = CrateInfo::new(tcx, target_cpu);
|
||||||
|
|
||||||
|
|
|
@ -809,7 +809,7 @@ impl CrateInfo {
|
||||||
.collect();
|
.collect();
|
||||||
let local_crate_name = tcx.crate_name(LOCAL_CRATE);
|
let local_crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
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| {
|
let windows_subsystem = subsystem.map(|subsystem| {
|
||||||
if subsystem != sym::windows && subsystem != sym::console {
|
if subsystem != sym::windows && subsystem != sym::console {
|
||||||
tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
|
tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
|
||||||
|
|
|
@ -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`.
|
// This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
|
||||||
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
|
'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() {
|
for i in 0..op.layout.fields.count() {
|
||||||
let field = op.extract_field(bx, i);
|
let field = op.extract_field(bx, i);
|
||||||
|
@ -959,7 +959,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
Immediate(_) => {
|
Immediate(_) => {
|
||||||
// See comment above explaining why we peel these newtypes
|
// See comment above explaining why we peel these newtypes
|
||||||
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
|
'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() {
|
for i in 0..op.layout.fields.count() {
|
||||||
let field = op.extract_field(bx, i);
|
let field = op.extract_field(bx, i);
|
||||||
|
|
|
@ -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
|
where `'a` is universally quantified and `'b` is substituted by a specific
|
||||||
lifetime. It is not allowed to explicitly specify early-bound lifetime
|
lifetime. It is not allowed to explicitly specify early-bound lifetime
|
||||||
arguments when late-bound lifetime parameters are present (as for `bar_fn2`,
|
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
|
types that are constrained by early-bound parameters can be specified (as for
|
||||||
`bar_fn3`).
|
`bar_fn3`).
|
||||||
|
|
|
@ -776,16 +776,14 @@ impl SyntaxExtension {
|
||||||
let allow_internal_unstable =
|
let allow_internal_unstable =
|
||||||
attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>();
|
attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>();
|
||||||
|
|
||||||
let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe);
|
let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe);
|
||||||
let local_inner_macros = sess
|
let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
|
||||||
.find_by_name(attrs, sym::macro_export)
|
|
||||||
.and_then(|macro_export| macro_export.meta_item_list())
|
.and_then(|macro_export| macro_export.meta_item_list())
|
||||||
.map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros));
|
.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);
|
tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
|
||||||
|
|
||||||
let (builtin_name, helper_attrs) = sess
|
let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro)
|
||||||
.find_by_name(attrs, sym::rustc_builtin_macro)
|
|
||||||
.map(|attr| {
|
.map(|attr| {
|
||||||
// Override `helper_attrs` passed above if it's a built-in macro,
|
// 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.
|
// marking `proc_macro_derive` macros as built-in is not a realistic use case.
|
||||||
|
|
|
@ -31,6 +31,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||||
use rustc_middle::middle::stability::AllowUnstable;
|
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::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::DynKind;
|
use rustc_middle::ty::DynKind;
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
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 param_env = tcx.param_env(block.owner.to_def_id());
|
||||||
let cause = ObligationCause::misc(span, block.owner.def_id);
|
let cause = ObligationCause::misc(span, block.owner.def_id);
|
||||||
|
|
||||||
let mut fulfillment_errors = Vec::new();
|
let mut fulfillment_errors = Vec::new();
|
||||||
let mut applicable_candidates: Vec<_> = candidates
|
let mut applicable_candidates: Vec<_> = infcx.probe(|_| {
|
||||||
.iter()
|
let universe = infcx.create_next_universe();
|
||||||
.filter_map(|&(impl_, (assoc_item, def_scope))| {
|
|
||||||
infcx.probe(|_| {
|
|
||||||
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
|
|
||||||
|
|
||||||
let impl_ty = tcx.type_of(impl_);
|
// Regions are not considered during selection.
|
||||||
let impl_substs = infcx.fresh_item_substs(impl_);
|
let self_ty = tcx.replace_escaping_bound_vars_uncached(
|
||||||
let impl_ty = impl_ty.subst(tcx, impl_substs);
|
self_ty,
|
||||||
let impl_ty = ocx.normalize(&cause, param_env, impl_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.
|
candidates
|
||||||
// FIXME(fmease): Should we use `eq` here?
|
.iter()
|
||||||
ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
|
.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_ty = tcx.type_of(impl_);
|
||||||
let impl_bounds = tcx.predicates_of(impl_);
|
let impl_substs = infcx.fresh_item_substs(impl_);
|
||||||
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
|
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(
|
// Check whether the impl imposes obligations we have to worry about.
|
||||||
|_, _| cause.clone(),
|
let impl_bounds = tcx.predicates_of(impl_);
|
||||||
param_env,
|
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
|
||||||
impl_bounds,
|
|
||||||
);
|
|
||||||
|
|
||||||
ocx.register_obligations(impl_obligations);
|
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
|
||||||
|
|
||||||
let mut errors = ocx.select_where_possible();
|
let impl_obligations = traits::predicates_for_generics(
|
||||||
if !errors.is_empty() {
|
|_, _| cause.clone(),
|
||||||
fulfillment_errors.append(&mut errors);
|
param_env,
|
||||||
return None;
|
impl_bounds,
|
||||||
}
|
);
|
||||||
|
|
||||||
// FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
|
ocx.register_obligations(impl_obligations);
|
||||||
Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
|
|
||||||
|
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 {
|
if applicable_candidates.len() > 1 {
|
||||||
return Err(self.complain_about_ambiguous_inherent_assoc_type(
|
return Err(self.complain_about_ambiguous_inherent_assoc_type(
|
||||||
|
|
|
@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
let deref_kind = if checked_ty.is_box() {
|
let deref_kind = if checked_ty.is_box() {
|
||||||
"unboxing the value"
|
"unboxing the value"
|
||||||
} else if checked_ty.is_region_ptr() {
|
} else if checked_ty.is_ref() {
|
||||||
"dereferencing the borrow"
|
"dereferencing the borrow"
|
||||||
} else {
|
} else {
|
||||||
"dereferencing the type"
|
"dereferencing the type"
|
||||||
|
|
|
@ -1182,7 +1182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.inputs()
|
.inputs()
|
||||||
.skip_binder()
|
.skip_binder()
|
||||||
.get(0)
|
.get(0)
|
||||||
.filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
|
.filter(|ty| ty.is_ref() && !rcvr_ty.is_ref())
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(rcvr_ty),
|
.unwrap_or(rcvr_ty),
|
||||||
};
|
};
|
||||||
|
|
|
@ -591,8 +591,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intercrate(mut self) -> Self {
|
pub fn intercrate(mut self, intercrate: bool) -> Self {
|
||||||
self.intercrate = true;
|
self.intercrate = intercrate;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use rustc_ast::attr;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
@ -8,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
|
||||||
|
|
||||||
for id in tcx.hir().items() {
|
for id in tcx.hir().items() {
|
||||||
let attrs = tcx.hir().attrs(id.hir_id());
|
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);
|
decls = Some(id.owner_id.def_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -505,7 +505,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
|
||||||
.opts
|
.opts
|
||||||
.crate_name
|
.crate_name
|
||||||
.clone()
|
.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());
|
.unwrap_or_else(|| sess.io.input.filestem().to_owned());
|
||||||
|
|
||||||
OutputFilenames::new(
|
OutputFilenames::new(
|
||||||
|
|
|
@ -358,29 +358,29 @@ impl EarlyLintPass for UnsafeCode {
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ItemKind::Fn(..) => {
|
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);
|
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);
|
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);
|
self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ItemKind::Static(..) => {
|
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);
|
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);
|
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);
|
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) {
|
fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
|
||||||
if let ast::AssocItemKind::Fn(..) = it.kind {
|
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);
|
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);
|
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1123,12 +1123,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
||||||
};
|
};
|
||||||
match it.kind {
|
match it.kind {
|
||||||
hir::ItemKind::Fn(.., ref generics, _) => {
|
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);
|
check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ItemKind::Const(..) => {
|
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)
|
// account for "pub const" (#45562)
|
||||||
let start = cx
|
let start = cx
|
||||||
.tcx
|
.tcx
|
||||||
|
@ -1152,9 +1152,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
||||||
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
|
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
|
||||||
for it in *items {
|
for it in *items {
|
||||||
if let hir::AssocItemKind::Fn { .. } = it.kind {
|
if let hir::AssocItemKind::Fn { .. } = it.kind {
|
||||||
if let Some(no_mangle_attr) = cx
|
if let Some(no_mangle_attr) =
|
||||||
.sess()
|
attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
|
||||||
.find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
|
|
||||||
{
|
{
|
||||||
check_no_mangle_on_generic_fn(
|
check_no_mangle_on_generic_fn(
|
||||||
no_mangle_attr,
|
no_mangle_attr,
|
||||||
|
@ -1836,7 +1835,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
|
||||||
}
|
}
|
||||||
|
|
||||||
let attrs = cx.tcx.hir().attrs(it.hir_id());
|
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);
|
cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,8 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
||||||
let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
|
let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
|
||||||
Some(Ident::from_str(name))
|
Some(Ident::from_str(name))
|
||||||
} else {
|
} else {
|
||||||
cx.sess()
|
attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
|
||||||
.find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
|
|
||||||
.and_then(|attr| attr.meta())
|
.and_then(|attr| attr.meta())
|
||||||
.and_then(|meta| {
|
.and_then(|meta| {
|
||||||
meta.name_value_literal().and_then(|lit| {
|
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<'_>) {
|
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||||
let attrs = cx.tcx.hir().attrs(it.hir_id());
|
let attrs = cx.tcx.hir().attrs(it.hir_id());
|
||||||
match it.kind {
|
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);
|
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
|
||||||
}
|
}
|
||||||
hir::ItemKind::Const(..) => {
|
hir::ItemKind::Const(..) => {
|
||||||
|
|
|
@ -6,11 +6,11 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob
|
||||||
|
|
||||||
use rustc_ast::expand::allocator::AllocatorKind;
|
use rustc_ast::expand::allocator::AllocatorKind;
|
||||||
use rustc_ast::{self as ast, *};
|
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::svh::Svh;
|
||||||
use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard};
|
use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard};
|
||||||
use rustc_expand::base::SyntaxExtension;
|
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_hir::definitions::Definitions;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
@ -46,9 +46,8 @@ pub struct CStore {
|
||||||
/// This crate has a `#[alloc_error_handler]` item.
|
/// This crate has a `#[alloc_error_handler]` item.
|
||||||
has_alloc_error_handler: bool,
|
has_alloc_error_handler: bool,
|
||||||
|
|
||||||
/// This map is used to verify we get no hash conflicts between
|
/// The interned [StableCrateId]s.
|
||||||
/// `StableCrateId` values.
|
pub(crate) stable_crate_ids: StableCrateIdMap,
|
||||||
pub(crate) stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
|
|
||||||
|
|
||||||
/// Unused externs of the crate
|
/// Unused externs of the crate
|
||||||
unused_externs: Vec<Symbol>,
|
unused_externs: Vec<Symbol>,
|
||||||
|
@ -144,9 +143,21 @@ impl CStore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_new_crate_num(&mut self) -> CrateNum {
|
fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError> {
|
||||||
self.metas.push(None);
|
assert_eq!(self.metas.len(), self.stable_crate_ids.len());
|
||||||
CrateNum::new(self.metas.len() - 1)
|
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 {
|
pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
|
||||||
|
@ -247,7 +258,7 @@ impl CStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(sess: &Session) -> 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);
|
stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
|
||||||
CStore {
|
CStore {
|
||||||
// We add an empty entry for LOCAL_CRATE (which maps to zero) in
|
// We add an empty entry for LOCAL_CRATE (which maps to zero) in
|
||||||
|
@ -342,42 +353,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||||
None
|
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(
|
fn register_crate(
|
||||||
&mut self,
|
&mut self,
|
||||||
host_lib: Option<Library>,
|
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);
|
self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep);
|
||||||
|
|
||||||
// Claim this crate number and cache it
|
// 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!(
|
info!(
|
||||||
"register crate `{}` (cnum = {}. private_dep = {})",
|
"register crate `{}` (cnum = {}. private_dep = {})",
|
||||||
|
@ -432,14 +407,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||||
None
|
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(
|
let crate_metadata = CrateMetadata::new(
|
||||||
self.sess,
|
self.sess,
|
||||||
&self.cstore,
|
&self.cstore,
|
||||||
|
@ -720,8 +687,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||||
// compilation mode also comes into play.
|
// compilation mode also comes into play.
|
||||||
let desired_strategy = self.sess.panic_strategy();
|
let desired_strategy = self.sess.panic_strategy();
|
||||||
let mut runtime_found = false;
|
let mut runtime_found = false;
|
||||||
let mut needs_panic_runtime =
|
let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
|
||||||
self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime);
|
|
||||||
|
|
||||||
for (cnum, data) in self.cstore.iter_crate_data() {
|
for (cnum, data) in self.cstore.iter_crate_data() {
|
||||||
needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
|
needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
|
||||||
|
@ -789,7 +755,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||||
info!("loading profiler");
|
info!("loading profiler");
|
||||||
|
|
||||||
let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
|
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);
|
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) {
|
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, ..] => {
|
[span1, span2, ..] => {
|
||||||
self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
|
self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
spans => !spans.is_empty(),
|
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, ..] => {
|
[span1, span2, ..] => {
|
||||||
self.sess
|
self.sess
|
||||||
.emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
|
.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
|
// Check to see if we actually need an allocator. This desire comes
|
||||||
// about through the `#![needs_allocator]` attribute and is typically
|
// about through the `#![needs_allocator]` attribute and is typically
|
||||||
// written down in liballoc.
|
// 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())
|
&& !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -881,7 +847,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||||
// allocator. At this point our allocator request is typically fulfilled
|
// allocator. At this point our allocator request is typically fulfilled
|
||||||
// by the standard library, denoted by the `#![default_lib_allocator]`
|
// by the standard library, denoted by the `#![default_lib_allocator]`
|
||||||
// attribute.
|
// 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.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
|
||||||
{
|
{
|
||||||
self.sess.emit_err(errors::GlobalAllocRequired);
|
self.sess.emit_err(errors::GlobalAllocRequired);
|
||||||
|
@ -1003,7 +969,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
None => item.ident.name,
|
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
|
CrateDepKind::MacrosOnly
|
||||||
} else {
|
} else {
|
||||||
CrateDepKind::Explicit
|
CrateDepKind::Explicit
|
||||||
|
@ -1049,16 +1015,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
|
fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
|
||||||
struct Finder<'a> {
|
struct Finder {
|
||||||
sess: &'a Session,
|
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
spans: Vec<Span>,
|
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) {
|
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||||
if item.ident.name == self.name
|
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);
|
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 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);
|
visit::walk_crate(&mut f, krate);
|
||||||
f.spans
|
f.spans
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
|
fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
|
||||||
struct Finder<'a> {
|
struct Finder {
|
||||||
sess: &'a Session,
|
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
spans: Vec<Span>,
|
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) {
|
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||||
if item.ident.name == self.name
|
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);
|
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 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);
|
visit::walk_crate(&mut f, krate);
|
||||||
f.spans
|
f.spans
|
||||||
}
|
}
|
||||||
|
|
|
@ -1709,10 +1709,6 @@ impl CrateMetadata {
|
||||||
self.root.name
|
self.root.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn stable_crate_id(&self) -> StableCrateId {
|
|
||||||
self.root.stable_crate_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn hash(&self) -> Svh {
|
pub(crate) fn hash(&self) -> Svh {
|
||||||
self.root.hash
|
self.root.hash
|
||||||
}
|
}
|
||||||
|
|
|
@ -595,7 +595,10 @@ impl CrateStore for CStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum {
|
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
|
/// Returns the `DefKey` for a given `DefId`. This indicates the
|
||||||
|
|
|
@ -681,17 +681,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
|
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
|
||||||
has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
|
has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
|
||||||
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
|
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
|
||||||
has_default_lib_allocator: tcx
|
has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator),
|
||||||
.sess
|
|
||||||
.contains_name(&attrs, sym::default_lib_allocator),
|
|
||||||
proc_macro_data,
|
proc_macro_data,
|
||||||
debugger_visualizers,
|
debugger_visualizers,
|
||||||
compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
|
compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins),
|
||||||
needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
|
needs_allocator: attr::contains_name(&attrs, sym::needs_allocator),
|
||||||
needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
|
needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime),
|
||||||
no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
|
no_builtins: attr::contains_name(&attrs, sym::no_builtins),
|
||||||
panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
|
panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
|
||||||
profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
|
profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
|
||||||
symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
|
symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
|
||||||
|
|
||||||
crate_deps,
|
crate_deps,
|
||||||
|
@ -1747,11 +1745,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
// Proc-macros may have attributes like `#[allow_internal_unstable]`,
|
// Proc-macros may have attributes like `#[allow_internal_unstable]`,
|
||||||
// so downstream crates need access to them.
|
// so downstream crates need access to them.
|
||||||
let attrs = hir.attrs(proc_macro);
|
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
|
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
|
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.
|
// This unwrap chain should have been checked by the proc-macro harness.
|
||||||
name = attr.meta_item_list().unwrap()[0]
|
name = attr.meta_item_list().unwrap()[0]
|
||||||
.meta_item()
|
.meta_item()
|
||||||
|
|
|
@ -63,15 +63,14 @@ impl Certainty {
|
||||||
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
|
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
|
||||||
(Certainty::Yes, Certainty::Maybe(_)) => other,
|
(Certainty::Yes, Certainty::Maybe(_)) => other,
|
||||||
(Certainty::Maybe(_), Certainty::Yes) => self,
|
(Certainty::Maybe(_), Certainty::Yes) => self,
|
||||||
(Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
|
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
|
||||||
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::Overflow))
|
||||||
|
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity))
|
||||||
|
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
|
||||||
|
Certainty::Maybe(MaybeCause::Overflow)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ use crate::ty::{
|
||||||
TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility,
|
TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility,
|
||||||
};
|
};
|
||||||
use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
|
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::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::intern::Interned;
|
use rustc_data_structures::intern::Interned;
|
||||||
|
@ -2520,9 +2520,9 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
providers.extern_mod_stmt_cnum =
|
providers.extern_mod_stmt_cnum =
|
||||||
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
|
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
|
||||||
providers.is_panic_runtime =
|
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 =
|
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| {
|
providers.has_panic_handler = |tcx, LocalCrate| {
|
||||||
// We want to check if the panic handler was defined in this crate
|
// 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())
|
tcx.lang_items().panic_impl().map_or(false, |did| did.is_local())
|
||||||
|
|
|
@ -1925,11 +1925,6 @@ impl<'tcx> Ty<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_region_ptr(self) -> bool {
|
|
||||||
matches!(self.kind(), Ref(..))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_mutable_ptr(self) -> bool {
|
pub fn is_mutable_ptr(self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
|
@ -1956,7 +1951,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
/// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
|
/// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_any_ptr(self) -> bool {
|
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]
|
#[inline]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::build::expr::as_place::PlaceBuilder;
|
||||||
use crate::build::scope::DropKind;
|
use crate::build::scope::DropKind;
|
||||||
use rustc_apfloat::ieee::{Double, Single};
|
use rustc_apfloat::ieee::{Double, Single};
|
||||||
use rustc_apfloat::Float;
|
use rustc_apfloat::Float;
|
||||||
|
use rustc_ast::attr;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
|
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
|
@ -680,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Some functions always have overflow checks enabled,
|
// Some functions always have overflow checks enabled,
|
||||||
// however, they may not get codegen'd, depending on
|
// however, they may not get codegen'd, depending on
|
||||||
// the settings for the crate they are codegened in.
|
// 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.
|
// Respect -C overflow-checks.
|
||||||
check_overflow |= tcx.sess.overflow_checks();
|
check_overflow |= tcx.sess.overflow_checks();
|
||||||
// Constants always need overflow checks.
|
// Constants always need overflow checks.
|
||||||
|
|
|
@ -185,7 +185,7 @@ impl<'tcx> Cx<'tcx> {
|
||||||
if self.typeck_results().is_coercion_cast(source.hir_id) {
|
if self.typeck_results().is_coercion_cast(source.hir_id) {
|
||||||
// Convert the lexpr to a vexpr.
|
// Convert the lexpr to a vexpr.
|
||||||
ExprKind::Use { source: self.mirror_expr(source) }
|
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
|
// Special cased so that we can type check that the element
|
||||||
// type of the source matches the pointed to type of the
|
// type of the source matches the pointed to type of the
|
||||||
// destination.
|
// destination.
|
||||||
|
|
|
@ -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_found_doc_comment = expected identifier, found doc comment
|
||||||
parse_expected_identifier = expected identifier
|
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
|
parse_sugg_remove_comma = remove this comma
|
||||||
|
|
||||||
|
|
|
@ -888,12 +888,12 @@ pub(crate) struct InvalidMetaItem {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
parse_sugg_escape_to_use_as_identifier,
|
parse_sugg_escape_identifier,
|
||||||
style = "verbose",
|
style = "verbose",
|
||||||
applicability = "maybe-incorrect",
|
applicability = "maybe-incorrect",
|
||||||
code = "r#"
|
code = "r#"
|
||||||
)]
|
)]
|
||||||
pub(crate) struct SuggEscapeToUseAsIdentifier {
|
pub(crate) struct SuggEscapeIdentifier {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub ident_name: String,
|
pub ident_name: String,
|
||||||
|
@ -937,7 +937,7 @@ impl ExpectedIdentifierFound {
|
||||||
pub(crate) struct ExpectedIdentifier {
|
pub(crate) struct ExpectedIdentifier {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub token: Token,
|
pub token: Token,
|
||||||
pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
|
pub suggest_raw: Option<SuggEscapeIdentifier>,
|
||||||
pub suggest_remove_comma: Option<SuggRemoveComma>,
|
pub suggest_remove_comma: Option<SuggRemoveComma>,
|
||||||
pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
|
pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
|
||||||
}
|
}
|
||||||
|
@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[help(parse_invalid_identifier_with_leading_number)]
|
#[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(crate) struct ExpectedSemi {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
|
@ -6,14 +6,14 @@ use super::{
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
|
AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
|
||||||
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
|
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
|
||||||
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
|
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
|
||||||
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||||
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
||||||
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
|
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
|
||||||
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
|
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
|
||||||
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
|
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
|
||||||
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
|
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
|
||||||
StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
|
StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma,
|
||||||
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
||||||
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
|
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
|
||||||
};
|
};
|
||||||
|
@ -38,7 +38,7 @@ use rustc_errors::{
|
||||||
use rustc_session::errors::ExprParenthesesNeeded;
|
use rustc_session::errors::ExprParenthesesNeeded;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
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::mem::take;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use thin_vec::{thin_vec, ThinVec};
|
use thin_vec::{thin_vec, ThinVec};
|
||||||
|
@ -268,7 +268,21 @@ impl<'a> Parser<'a> {
|
||||||
self.sess.source_map().span_to_snippet(span)
|
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 = &[
|
let valid_follow = &[
|
||||||
TokenKind::Eq,
|
TokenKind::Eq,
|
||||||
TokenKind::Colon,
|
TokenKind::Colon,
|
||||||
|
@ -281,31 +295,51 @@ impl<'a> Parser<'a> {
|
||||||
TokenKind::CloseDelim(Delimiter::Parenthesis),
|
TokenKind::CloseDelim(Delimiter::Parenthesis),
|
||||||
];
|
];
|
||||||
|
|
||||||
let suggest_raw = match self.token.ident() {
|
let mut recovered_ident = None;
|
||||||
Some((ident, false))
|
// we take this here so that the correct original token is retained in
|
||||||
if ident.is_raw_guess()
|
// the diagnostic, regardless of eager recovery.
|
||||||
&& self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
|
let bad_token = self.token.clone();
|
||||||
{
|
|
||||||
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 suggest_remove_comma = (self.token == token::Comma
|
// suggest prepending a keyword in identifier position with `r#`
|
||||||
&& self.look_ahead(1, |t| t.is_ident()))
|
let suggest_raw = if let Some((ident, false)) = self.token.ident()
|
||||||
.then_some(SuggRemoveComma { span: self.token.span });
|
&& ident.is_raw_guess()
|
||||||
|
&& self.look_ahead(1, |t| valid_follow.contains(&t.kind))
|
||||||
|
{
|
||||||
|
recovered_ident = Some((ident, true));
|
||||||
|
|
||||||
let help_cannot_start_number =
|
// `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
|
||||||
self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber);
|
// 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 {
|
let err = ExpectedIdentifier {
|
||||||
span: self.token.span,
|
span: bad_token.span,
|
||||||
token: self.token.clone(),
|
token: bad_token,
|
||||||
suggest_raw,
|
suggest_raw,
|
||||||
suggest_remove_comma,
|
suggest_remove_comma,
|
||||||
help_cannot_start_number,
|
help_cannot_start_number,
|
||||||
|
@ -314,6 +348,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// if the token we have is a `<`
|
// if the token we have is a `<`
|
||||||
// it *might* be a misplaced generic
|
// it *might* be a misplaced generic
|
||||||
|
// FIXME: could we recover with this?
|
||||||
if self.token == token::Lt {
|
if self.token == token::Lt {
|
||||||
// all keywords that could have generic applied
|
// all keywords that could have generic applied
|
||||||
let valid_prev_keywords =
|
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
|
/// 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.
|
/// 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, .. })
|
/// Returns the number of characters (bytes) composing the invalid portion
|
||||||
// ensure that the integer literal is followed by a *invalid*
|
/// of the identifier and the valid portion of the identifier.
|
||||||
// suffix: this is how we know that it is a identifier with an
|
pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
|
||||||
// invalid beginning.
|
// ensure that the integer literal is followed by a *invalid*
|
||||||
if rustc_ast::MetaItemLit::from_token(&self.token).is_none()
|
// 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(
|
pub(super) fn expected_one_of_not_found(
|
||||||
|
|
|
@ -1181,7 +1181,7 @@ impl<'a> Parser<'a> {
|
||||||
defaultness: Defaultness,
|
defaultness: Defaultness,
|
||||||
) -> PResult<'a, ItemInfo> {
|
) -> PResult<'a, ItemInfo> {
|
||||||
let impl_span = self.token.span;
|
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
|
// Only try to recover if this is implementing a trait for a type
|
||||||
let mut impl_info = match self.parse_item_impl(attrs, defaultness) {
|
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`
|
/// Parses a field identifier. Specialized version of `parse_ident_common`
|
||||||
/// for better diagnostics and suggestions.
|
/// for better diagnostics and suggestions.
|
||||||
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
|
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() {
|
if !is_raw && ident.is_reserved() {
|
||||||
let snapshot = self.create_snapshot_for_diagnostic();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let err = if self.check_fn_front_matter(false, Case::Sensitive) {
|
let err = if self.check_fn_front_matter(false, Case::Sensitive) {
|
||||||
|
@ -1776,7 +1776,7 @@ impl<'a> Parser<'a> {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.cancel();
|
err.cancel();
|
||||||
self.restore_snapshot(snapshot);
|
self.restore_snapshot(snapshot);
|
||||||
self.expected_ident_found()
|
self.expected_ident_found_err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if self.eat_keyword(kw::Struct) {
|
} else if self.eat_keyword(kw::Struct) {
|
||||||
|
@ -1792,11 +1792,11 @@ impl<'a> Parser<'a> {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.cancel();
|
err.cancel();
|
||||||
self.restore_snapshot(snapshot);
|
self.restore_snapshot(snapshot);
|
||||||
self.expected_ident_found()
|
self.expected_ident_found_err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut err = self.expected_ident_found();
|
let mut err = self.expected_ident_found_err();
|
||||||
if self.eat_keyword_noexpect(kw::Let)
|
if self.eat_keyword_noexpect(kw::Let)
|
||||||
&& let removal_span = self.prev_token.span.until(self.token.span)
|
&& let removal_span = self.prev_token.span.until(self.token.span)
|
||||||
&& let Ok(ident) = self.parse_ident_common(false)
|
&& let Ok(ident) = self.parse_ident_common(false)
|
||||||
|
|
|
@ -42,8 +42,7 @@ use thin_vec::ThinVec;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter,
|
IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
|
||||||
NonStringAbiLiteral,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
|
@ -552,21 +551,11 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_ident_common(true)
|
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> {
|
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() {
|
if !is_raw && ident.is_reserved() {
|
||||||
let mut err = self.expected_ident_found();
|
let mut err = self.expected_ident_found_err();
|
||||||
if recover {
|
if recover {
|
||||||
err.emit();
|
err.emit();
|
||||||
} else {
|
} else {
|
||||||
|
@ -577,6 +566,21 @@ impl<'a> Parser<'a> {
|
||||||
Ok(ident)
|
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.
|
/// 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
|
/// This method will automatically add `tok` to `expected_tokens` if `tok` is not
|
||||||
|
|
|
@ -348,10 +348,6 @@ impl<'a> Parser<'a> {
|
||||||
lo = self.token.span;
|
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 {
|
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
|
||||||
self.parse_pat_deref(expected)?
|
self.parse_pat_deref(expected)?
|
||||||
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
||||||
|
@ -395,7 +391,13 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
PatKind::Lit(const_expr)
|
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`
|
// Parse `ident @ pat`
|
||||||
// This can give false positives and parse nullary enums,
|
// This can give false positives and parse nullary enums,
|
||||||
// they are dealt with later in resolve.
|
// 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`.
|
// 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::Interpolated(nt) = &self.token.kind {
|
||||||
if let token::NtPat(_) = **nt {
|
if let token::NtPat(_) = **nt {
|
||||||
self.expected_ident_found().emit();
|
self.expected_ident_found_err().emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1907,7 +1907,7 @@ impl CheckAttrVisitor<'_> {
|
||||||
match target {
|
match target {
|
||||||
Target::Fn => {
|
Target::Fn => {
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
if self.tcx.sess.is_proc_macro_attr(attr) {
|
if attr.is_proc_macro_attr() {
|
||||||
debug!("Is proc macro attr");
|
debug!("Is proc macro attr");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use rustc_ast::attr;
|
||||||
use rustc_ast::entry::EntryPointType;
|
use rustc_ast::entry::EntryPointType;
|
||||||
use rustc_errors::error_code;
|
use rustc_errors::error_code;
|
||||||
use rustc_hir::def::DefKind;
|
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 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;
|
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.
|
// 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 {
|
fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
|
||||||
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
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
|
EntryPointType::Start
|
||||||
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
|
} else if attr::contains_name(attrs, sym::rustc_main) {
|
||||||
EntryPointType::RustcMainAttr
|
EntryPointType::RustcMainAttr
|
||||||
} else {
|
} else {
|
||||||
if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id())
|
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> {
|
fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
|
||||||
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
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<'_>) {
|
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
||||||
|
|
|
@ -570,7 +570,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
ast::UseTreeKind::Glob => {
|
ast::UseTreeKind::Glob => {
|
||||||
let kind = ImportKind::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),
|
max_vis: Cell::new(None),
|
||||||
id,
|
id,
|
||||||
};
|
};
|
||||||
|
@ -685,7 +685,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
expansion.to_expn_id(),
|
expansion.to_expn_id(),
|
||||||
item.span,
|
item.span,
|
||||||
parent.no_implicit_prelude
|
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));
|
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
|
// If the structure is marked as non_exhaustive then lower the visibility
|
||||||
// to within the crate.
|
// to within the crate.
|
||||||
let mut ctor_vis = if vis.is_public()
|
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)
|
ty::Visibility::Restricted(CRATE_DEF_ID)
|
||||||
} else {
|
} 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)> {
|
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));
|
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));
|
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(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
|
||||||
if let Some(ident) = nested_meta.ident() {
|
if let Some(ident) = nested_meta.ident() {
|
||||||
return Some((MacroKind::Derive, ident, ident.span));
|
return Some((MacroKind::Derive, ident, ident.span));
|
||||||
|
@ -1228,7 +1227,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
if macro_rules {
|
if macro_rules {
|
||||||
let ident = ident.normalize_to_macros_2_0();
|
let ident = ident.normalize_to_macros_2_0();
|
||||||
self.r.macro_names.insert(ident);
|
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 {
|
let vis = if is_macro_export {
|
||||||
ty::Visibility::Public
|
ty::Visibility::Public
|
||||||
} else {
|
} else {
|
||||||
|
@ -1488,13 +1487,12 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
self.r.visibilities.insert(def_id, vis);
|
self.r.visibilities.insert(def_id, vis);
|
||||||
|
|
||||||
// If the variant is marked as non_exhaustive then lower the visibility to within the crate.
|
// If the variant is marked as non_exhaustive then lower the visibility to within the crate.
|
||||||
let ctor_vis = if vis.is_public()
|
let ctor_vis =
|
||||||
&& self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive)
|
if vis.is_public() && attr::contains_name(&variant.attrs, sym::non_exhaustive) {
|
||||||
{
|
ty::Visibility::Restricted(CRATE_DEF_ID)
|
||||||
ty::Visibility::Restricted(CRATE_DEF_ID)
|
} else {
|
||||||
} else {
|
vis
|
||||||
vis
|
};
|
||||||
};
|
|
||||||
|
|
||||||
// Define a constructor name in the value namespace.
|
// Define a constructor name in the value namespace.
|
||||||
if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) {
|
if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ extern crate tracing;
|
||||||
|
|
||||||
use rustc_arena::{DroplessArena, TypedArena};
|
use rustc_arena::{DroplessArena, TypedArena};
|
||||||
use rustc_ast::node_id::NodeMap;
|
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_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_data_structures::intern::Interned;
|
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),
|
ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
|
||||||
ExpnId::root(),
|
ExpnId::root(),
|
||||||
krate.spans.inner_span,
|
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,
|
&mut module_map,
|
||||||
);
|
);
|
||||||
let empty_module = arenas.new_module(
|
let empty_module = arenas.new_module(
|
||||||
|
@ -1222,9 +1222,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
.map(|(name, _)| (Ident::from_str(name), Default::default()))
|
.map(|(name, _)| (Ident::from_str(name), Default::default()))
|
||||||
.collect();
|
.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());
|
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());
|
extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::Namespace::*;
|
||||||
use crate::{BuiltinMacroState, Determinacy};
|
use crate::{BuiltinMacroState, Determinacy};
|
||||||
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
|
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
|
||||||
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment};
|
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_ast_pretty::pprust;
|
||||||
use rustc_attr::StabilityLevel;
|
use rustc_attr::StabilityLevel;
|
||||||
use rustc_data_structures::intern::Interned;
|
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 {
|
pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
|
||||||
let mut registered_tools = RegisteredTools::default();
|
let mut registered_tools = RegisteredTools::default();
|
||||||
let krate = tcx.crate_for_resolver(()).borrow();
|
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() {
|
for nested_meta in attr.meta_item_list().unwrap_or_default() {
|
||||||
match nested_meta.ident() {
|
match nested_meta.ident() {
|
||||||
Some(ident) => {
|
Some(ident) => {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::errors::{
|
||||||
InvalidCharacterInCrateName,
|
InvalidCharacterInCrateName,
|
||||||
};
|
};
|
||||||
use crate::Session;
|
use crate::Session;
|
||||||
use rustc_ast as ast;
|
use rustc_ast::{self as ast, attr};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use std::path::{Path, PathBuf};
|
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
|
// 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.
|
// find both we ensure that they're the same later on as well.
|
||||||
let attr_crate_name =
|
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 {
|
if let Some(ref s) = sess.opts.crate_name {
|
||||||
let s = Symbol::intern(s);
|
let s = Symbol::intern(s);
|
||||||
|
|
|
@ -30,7 +30,7 @@ use rustc_macros::HashStable_Generic;
|
||||||
pub use rustc_span::def_id::StableCrateId;
|
pub use rustc_span::def_id::StableCrateId;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span};
|
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::asm::InlineAsmArch;
|
||||||
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
|
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
|
@ -1003,40 +1003,6 @@ impl Session {
|
||||||
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
|
|| 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 {
|
pub fn diagnostic_width(&self) -> usize {
|
||||||
let default_column_width = 140;
|
let default_column_width = 140;
|
||||||
if let Some(width) = self.opts.diagnostic_width {
|
if let Some(width) = self.opts.diagnostic_width {
|
||||||
|
|
|
@ -18,3 +18,4 @@ tracing = "0.1"
|
||||||
sha1 = "0.10.0"
|
sha1 = "0.10.0"
|
||||||
sha2 = "0.10.1"
|
sha2 = "0.10.1"
|
||||||
md5 = { package = "md-5", version = "0.10.0" }
|
md5 = { package = "md-5", version = "0.10.0" }
|
||||||
|
indexmap = { version = "1.9.1" }
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
use crate::{HashStableContext, Symbol};
|
use crate::{HashStableContext, Symbol};
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
||||||
|
use rustc_data_structures::unhash::Unhasher;
|
||||||
use rustc_data_structures::AtomicRef;
|
use rustc_data_structures::AtomicRef;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::fmt;
|
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! {
|
rustc_index::newtype_index! {
|
||||||
#[custom_encodable]
|
#[custom_encodable]
|
||||||
|
|
|
@ -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`.
|
/// Returns a `Span` that would enclose both `self` and `end`.
|
||||||
///
|
///
|
||||||
/// Note that this can also be used to extend the span "backwards":
|
/// Note that this can also be used to extend the span "backwards":
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use super::trait_goals::structural_traits::*;
|
use super::trait_goals::structural_traits::*;
|
||||||
use super::EvalCtxt;
|
use super::{EvalCtxt, SolverMode};
|
||||||
|
use crate::traits::coherence;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
@ -87,6 +88,8 @@ pub(super) enum CandidateSource {
|
||||||
pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
|
pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
|
||||||
fn self_ty(self) -> Ty<'tcx>;
|
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 with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
|
||||||
|
|
||||||
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
|
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_object_bound_candidates(goal, &mut candidates);
|
||||||
|
|
||||||
|
self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
|
||||||
|
|
||||||
candidates
|
candidates
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the self type of a goal is a projection, computing the relevant candidates is difficult.
|
/// 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
|
/// 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
|
/// self type to the list of candidates in case that succeeds. We also have to consider candidates with the
|
||||||
/// this case as projections as self types add
|
/// projection as a self type as well
|
||||||
// FIXME complete the unfinished sentence above
|
|
||||||
fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
|
fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, G>,
|
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)]
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
pub(super) fn merge_candidates_and_discard_reservation_impls(
|
pub(super) fn merge_candidates(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut candidates: Vec<Candidate<'tcx>>,
|
mut candidates: Vec<Candidate<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
match candidates.len() {
|
match candidates.len() {
|
||||||
0 => return Err(NoSolution),
|
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;
|
let mut i = 0;
|
||||||
'outer: while i < candidates.len() {
|
'outer: while i < candidates.len() {
|
||||||
for j in (0..candidates.len()).filter(|&j| i != j) {
|
for j in (0..candidates.len()).filter(|&j| i != j) {
|
||||||
if self.trait_candidate_should_be_dropped_in_favor_of(
|
if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
|
||||||
&candidates[i],
|
{
|
||||||
&candidates[j],
|
|
||||||
) {
|
|
||||||
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
|
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
|
||||||
candidates.swap_remove(i);
|
candidates.swap_remove(i);
|
||||||
continue 'outer;
|
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(candidates.pop().unwrap().result)
|
||||||
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trait_candidate_should_be_dropped_in_favor_of(
|
fn candidate_should_be_dropped_in_favor_of(
|
||||||
&self,
|
&self,
|
||||||
candidate: &Candidate<'tcx>,
|
candidate: &Candidate<'tcx>,
|
||||||
other: &Candidate<'tcx>,
|
other: &Candidate<'tcx>,
|
||||||
|
@ -528,20 +555,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
| (CandidateSource::BuiltinImpl, _) => false,
|
| (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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use rustc_span::DUMMY_SP;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use super::search_graph::{self, OverflowHandler};
|
use super::search_graph::{self, OverflowHandler};
|
||||||
|
use super::SolverMode;
|
||||||
use super::{search_graph::SearchGraph, Goal};
|
use super::{search_graph::SearchGraph, Goal};
|
||||||
|
|
||||||
pub struct EvalCtxt<'a, 'tcx> {
|
pub struct EvalCtxt<'a, 'tcx> {
|
||||||
|
@ -78,7 +79,9 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
||||||
&self,
|
&self,
|
||||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||||
) -> Result<(bool, Certainty), NoSolution> {
|
) -> 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 {
|
let mut ecx = EvalCtxt {
|
||||||
search_graph: &mut search_graph,
|
search_graph: &mut search_graph,
|
||||||
|
@ -101,6 +104,10 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> EvalCtxt<'a, '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.
|
/// The entry point of the solver.
|
||||||
///
|
///
|
||||||
/// This function deals with (coinductive) cycles, overflow, and caching
|
/// 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`.
|
// The actual solver logic happens in `ecx.compute_goal`.
|
||||||
search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
|
search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
|
||||||
let (ref infcx, goal, var_values) =
|
let intercrate = match search_graph.solver_mode() {
|
||||||
tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
|
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 {
|
let mut ecx = EvalCtxt {
|
||||||
infcx,
|
infcx,
|
||||||
var_values,
|
var_values,
|
||||||
|
|
|
@ -9,10 +9,6 @@
|
||||||
//! FIXME(@lcnr): Write that section. If you read this before then ask me
|
//! FIXME(@lcnr): Write that section. If you read this before then ask me
|
||||||
//! about it on zulip.
|
//! 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.
|
// FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
|
||||||
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
@ -41,6 +37,19 @@ mod trait_goals;
|
||||||
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
|
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
|
||||||
pub use fulfill::FulfillmentCtxt;
|
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 {
|
trait CanonicalResponseExt {
|
||||||
fn has_no_inference_or_external_constraints(&self) -> bool;
|
fn has_no_inference_or_external_constraints(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
@ -255,7 +264,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
return Err(NoSolution);
|
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.
|
// a subset of the constraints that all the other responses have.
|
||||||
let one = candidates[0];
|
let one = candidates[0];
|
||||||
if candidates[1..].iter().all(|resp| resp == &one) {
|
if candidates[1..].iter().all(|resp| resp == &one) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
// projection cache in the solver.
|
// projection cache in the solver.
|
||||||
if self.term_is_fully_unconstrained(goal) {
|
if self.term_is_fully_unconstrained(goal) {
|
||||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||||
self.merge_candidates_and_discard_reservation_impls(candidates)
|
self.merge_candidates(candidates)
|
||||||
} else {
|
} else {
|
||||||
let predicate = goal.predicate;
|
let predicate = goal.predicate;
|
||||||
let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term);
|
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()
|
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 {
|
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||||
self.with_self_ty(tcx, self_ty)
|
self.with_self_ty(tcx, self_ty)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
mod cache;
|
mod cache;
|
||||||
mod overflow;
|
mod overflow;
|
||||||
|
|
||||||
|
pub(super) use overflow::OverflowHandler;
|
||||||
|
|
||||||
use self::cache::ProvisionalEntry;
|
use self::cache::ProvisionalEntry;
|
||||||
pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
|
|
||||||
use cache::ProvisionalCache;
|
use cache::ProvisionalCache;
|
||||||
use overflow::OverflowData;
|
use overflow::OverflowData;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
|
@ -11,6 +12,8 @@ use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryRes
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use std::{collections::hash_map::Entry, mem};
|
use std::{collections::hash_map::Entry, mem};
|
||||||
|
|
||||||
|
use super::SolverMode;
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
pub struct StackDepth {}
|
pub struct StackDepth {}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +24,7 @@ struct StackElem<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct SearchGraph<'tcx> {
|
pub(super) struct SearchGraph<'tcx> {
|
||||||
|
mode: SolverMode,
|
||||||
/// The stack of goals currently being computed.
|
/// The stack of goals currently being computed.
|
||||||
///
|
///
|
||||||
/// An element is *deeper* in the stack if its index is *lower*.
|
/// 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> {
|
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 {
|
Self {
|
||||||
|
mode,
|
||||||
stack: Default::default(),
|
stack: Default::default(),
|
||||||
overflow_data: OverflowData::new(tcx),
|
overflow_data: OverflowData::new(tcx),
|
||||||
provisional_cache: ProvisionalCache::empty(),
|
provisional_cache: ProvisionalCache::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn solver_mode(&self) -> SolverMode {
|
||||||
|
self.mode
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn is_empty(&self) -> bool {
|
pub(super) fn is_empty(&self) -> bool {
|
||||||
self.stack.is_empty() && self.provisional_cache.is_empty()
|
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.
|
// 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.
|
// 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 {
|
if should_cache_globally {
|
||||||
tcx.new_solver_evaluation_cache.insert(
|
tcx.new_solver_evaluation_cache.insert(
|
||||||
current_goal.goal,
|
current_goal.goal,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use super::{assembly, EvalCtxt};
|
use super::{assembly, EvalCtxt, SolverMode};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::LangItem;
|
use rustc_hir::LangItem;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
@ -20,6 +20,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
self.self_ty()
|
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 {
|
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||||
self.with_self_ty(tcx, self_ty)
|
self.with_self_ty(tcx, self_ty)
|
||||||
}
|
}
|
||||||
|
@ -43,6 +47,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
return Err(NoSolution);
|
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| {
|
ecx.probe(|ecx| {
|
||||||
let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
|
let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
|
||||||
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
|
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()
|
.into_iter()
|
||||||
.map(|pred| goal.with(tcx, pred));
|
.map(|pred| goal.with(tcx, pred));
|
||||||
ecx.add_goals(where_clause_bounds);
|
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>>,
|
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||||
self.merge_candidates_and_discard_reservation_impls(candidates)
|
self.merge_candidates(candidates)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,8 +95,11 @@ pub fn overlapping_impls(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let infcx =
|
let infcx = tcx
|
||||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
|
.infer_ctxt()
|
||||||
|
.with_opaque_type_inference(DefiningAnchor::Bubble)
|
||||||
|
.intercrate(true)
|
||||||
|
.build();
|
||||||
let selcx = &mut SelectionContext::new(&infcx);
|
let selcx = &mut SelectionContext::new(&infcx);
|
||||||
let overlaps =
|
let overlaps =
|
||||||
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
|
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
|
// In the case where we detect an error, run the check again, but
|
||||||
// this time tracking intercrate ambiguity causes for better
|
// this time tracking intercrate ambiguity causes for better
|
||||||
// diagnostics. (These take time and can lead to false errors.)
|
// diagnostics. (These take time and can lead to false errors.)
|
||||||
let infcx =
|
let infcx = tcx
|
||||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
|
.infer_ctxt()
|
||||||
|
.with_opaque_type_inference(DefiningAnchor::Bubble)
|
||||||
|
.intercrate(true)
|
||||||
|
.build();
|
||||||
let selcx = &mut SelectionContext::new(&infcx);
|
let selcx = &mut SelectionContext::new(&infcx);
|
||||||
selcx.enable_tracking_intercrate_ambiguity_causes();
|
selcx.enable_tracking_intercrate_ambiguity_causes();
|
||||||
Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
|
Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
pub mod auto_trait;
|
pub mod auto_trait;
|
||||||
mod chalk_fulfill;
|
mod chalk_fulfill;
|
||||||
mod coherence;
|
pub(crate) mod coherence;
|
||||||
pub mod const_evaluatable;
|
pub mod const_evaluatable;
|
||||||
mod engine;
|
mod engine;
|
||||||
pub mod error_reporting;
|
pub mod error_reporting;
|
||||||
|
|
|
@ -539,7 +539,7 @@ fn make_thin_self_ptr<'tcx>(
|
||||||
// get a built-in pointer type
|
// get a built-in pointer type
|
||||||
let mut fat_pointer_layout = layout;
|
let mut fat_pointer_layout = layout;
|
||||||
'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
|
'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() {
|
for i in 0..fat_pointer_layout.fields.count() {
|
||||||
let field_layout = fat_pointer_layout.field(cx, i);
|
let field_layout = fat_pointer_layout.field(cx, i);
|
||||||
|
|
|
@ -209,6 +209,7 @@
|
||||||
#![feature(derive_const)]
|
#![feature(derive_const)]
|
||||||
#![feature(doc_cfg)]
|
#![feature(doc_cfg)]
|
||||||
#![feature(doc_notable_trait)]
|
#![feature(doc_notable_trait)]
|
||||||
|
#![feature(generic_arg_infer)]
|
||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
#![feature(exhaustive_patterns)]
|
#![feature(exhaustive_patterns)]
|
||||||
#![feature(doc_cfg_hide)]
|
#![feature(doc_cfg_hide)]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit a0c30f3e3c75adcd6ee7efc94014ebcead61c507
|
Subproject commit b655243782c18d3419439daa523782e0818ecf26
|
|
@ -1471,27 +1471,68 @@ impl Type {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if two types are "potentially the same".
|
pub(crate) fn is_borrowed_ref(&self) -> bool {
|
||||||
|
matches!(self, Type::BorrowedRef { .. })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if two types are "the same" for documentation purposes.
|
||||||
|
///
|
||||||
/// This is different from `Eq`, because it knows that things like
|
/// This is different from `Eq`, because it knows that things like
|
||||||
/// `Placeholder` are possible matches for everything.
|
/// `Placeholder` are possible matches for everything.
|
||||||
pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool {
|
///
|
||||||
match (self, other) {
|
/// This relation is not commutative when generics are involved:
|
||||||
|
///
|
||||||
|
/// ```ignore(private)
|
||||||
|
/// # // see types/tests.rs:is_same_generic for the real test
|
||||||
|
/// use rustdoc::format::cache::Cache;
|
||||||
|
/// use rustdoc::clean::types::{Type, PrimitiveType};
|
||||||
|
/// let cache = Cache::new(false);
|
||||||
|
/// let generic = Type::Generic(rustc_span::symbol::sym::Any);
|
||||||
|
/// let unit = Type::Primitive(PrimitiveType::Unit);
|
||||||
|
/// assert!(!generic.is_same(&unit, &cache));
|
||||||
|
/// assert!(unit.is_same(&generic, &cache));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// An owned type is also the same as its borrowed variants (this is commutative),
|
||||||
|
/// but `&T` is not the same as `&mut T`.
|
||||||
|
pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
|
||||||
|
// Strip the references so that it can compare the actual types, unless both are references.
|
||||||
|
// If both are references, leave them alone and compare the mutabilities later.
|
||||||
|
let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
|
||||||
|
(self.without_borrowed_ref(), other.without_borrowed_ref())
|
||||||
|
} else {
|
||||||
|
(self, other)
|
||||||
|
};
|
||||||
|
match (self_cleared, other_cleared) {
|
||||||
// Recursive cases.
|
// Recursive cases.
|
||||||
(Type::Tuple(a), Type::Tuple(b)) => {
|
(Type::Tuple(a), Type::Tuple(b)) => {
|
||||||
a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache))
|
a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
|
||||||
}
|
}
|
||||||
(Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache),
|
(Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
|
||||||
(Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache),
|
(Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
|
||||||
(Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
|
(Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
|
||||||
mutability == b_mutability && type_.is_same(b_type_, cache)
|
mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
Type::BorrowedRef { mutability, type_, .. },
|
Type::BorrowedRef { mutability, type_, .. },
|
||||||
Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
|
Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
|
||||||
) => mutability == b_mutability && type_.is_same(b_type_, cache),
|
) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
|
||||||
// Placeholders and generics are equal to all other types.
|
// Placeholders are equal to all other types.
|
||||||
(Type::Infer, _) | (_, Type::Infer) => true,
|
(Type::Infer, _) | (_, Type::Infer) => true,
|
||||||
(Type::Generic(_), _) | (_, Type::Generic(_)) => true,
|
// Generics match everything on the right, but not on the left.
|
||||||
|
// If both sides are generic, this returns true.
|
||||||
|
(_, Type::Generic(_)) => true,
|
||||||
|
(Type::Generic(_), _) => false,
|
||||||
|
// Paths account for both the path itself and its generics.
|
||||||
|
(Type::Path { path: a }, Type::Path { path: b }) => {
|
||||||
|
a.def_id() == b.def_id()
|
||||||
|
&& a.generics()
|
||||||
|
.zip(b.generics())
|
||||||
|
.map(|(ag, bg)| {
|
||||||
|
ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
|
||||||
|
})
|
||||||
|
.unwrap_or(true)
|
||||||
|
}
|
||||||
// Other cases, such as primitives, just use recursion.
|
// Other cases, such as primitives, just use recursion.
|
||||||
(a, b) => a
|
(a, b) => a
|
||||||
.def_id(cache)
|
.def_id(cache)
|
||||||
|
|
|
@ -69,3 +69,14 @@ fn should_not_trim() {
|
||||||
run_test("\t line1 \n\t line2", "line1 \nline2");
|
run_test("\t line1 \n\t line2", "line1 \nline2");
|
||||||
run_test(" \tline1 \n \tline2", "line1 \nline2");
|
run_test(" \tline1 \n \tline2", "line1 \nline2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_same_generic() {
|
||||||
|
use crate::clean::types::{PrimitiveType, Type};
|
||||||
|
use crate::formats::cache::Cache;
|
||||||
|
let cache = Cache::new(false);
|
||||||
|
let generic = Type::Generic(rustc_span::symbol::sym::Any);
|
||||||
|
let unit = Type::Primitive(PrimitiveType::Unit);
|
||||||
|
assert!(!generic.is_doc_subtype_of(&unit, &cache));
|
||||||
|
assert!(unit.is_doc_subtype_of(&generic, &cache));
|
||||||
|
}
|
||||||
|
|
|
@ -1294,7 +1294,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
|
||||||
if let Some(impls) = cx.cache().impls.get(&did) {
|
if let Some(impls) = cx.cache().impls.get(&did) {
|
||||||
for i in impls {
|
for i in impls {
|
||||||
let impl_ = i.inner_impl();
|
let impl_ = i.inner_impl();
|
||||||
if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
|
if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
|
||||||
// Two different types might have the same did,
|
// Two different types might have the same did,
|
||||||
// without actually being the same.
|
// without actually being the same.
|
||||||
continue;
|
continue;
|
||||||
|
@ -1330,7 +1330,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
|
||||||
|
|
||||||
for i in impls {
|
for i in impls {
|
||||||
let impl_ = i.inner_impl();
|
let impl_ = i.inner_impl();
|
||||||
if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
|
if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
|
||||||
// Two different types might have the same did,
|
// Two different types might have the same did,
|
||||||
// without actually being the same.
|
// without actually being the same.
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
|
||||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||||
if let Some(attr) = attr {
|
if let Some(attr) = attr {
|
||||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
||||||
} else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
|
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
|
||||||
check_must_use_candidate(
|
check_must_use_candidate(
|
||||||
cx,
|
cx,
|
||||||
sig.decl,
|
sig.decl,
|
||||||
|
@ -51,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
|
||||||
if let Some(attr) = attr {
|
if let Some(attr) = attr {
|
||||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
||||||
} else if is_public
|
} else if is_public
|
||||||
&& !is_proc_macro(cx.sess(), attrs)
|
&& !is_proc_macro(attrs)
|
||||||
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
||||||
{
|
{
|
||||||
check_must_use_candidate(
|
check_must_use_candidate(
|
||||||
|
@ -78,7 +78,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
|
||||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
||||||
} else if let hir::TraitFn::Provided(eid) = *eid {
|
} else if let hir::TraitFn::Provided(eid) = *eid {
|
||||||
let body = cx.tcx.hir().body(eid);
|
let body = cx.tcx.hir().body(eid);
|
||||||
if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
|
if attr.is_none() && is_public && !is_proc_macro(attrs) {
|
||||||
check_must_use_candidate(
|
check_must_use_candidate(
|
||||||
cx,
|
cx,
|
||||||
sig.decl,
|
sig.decl,
|
||||||
|
|
|
@ -145,8 +145,8 @@ pub fn get_unique_attr<'a>(
|
||||||
|
|
||||||
/// Return true if the attributes contain any of `proc_macro`,
|
/// Return true if the attributes contain any of `proc_macro`,
|
||||||
/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
|
/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
|
||||||
pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
|
pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool {
|
||||||
attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
|
attrs.iter().any(|attr| attr.is_proc_macro_attr())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the attributes contain `#[doc(hidden)]`
|
/// Return true if the attributes contain `#[doc(hidden)]`
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_ast::HasAttrs;
|
use rustc_ast::HasAttrs;
|
||||||
use rustc_span::{symbol::sym, Span, Symbol};
|
use rustc_span::{symbol::sym, Span};
|
||||||
|
|
||||||
use self::doc_comment::DocCommentFormatter;
|
use self::doc_comment::DocCommentFormatter;
|
||||||
use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle};
|
use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle};
|
||||||
|
@ -19,20 +19,6 @@ use crate::utils::{count_newlines, mk_sp};
|
||||||
|
|
||||||
mod doc_comment;
|
mod doc_comment;
|
||||||
|
|
||||||
pub(crate) fn contains_name(attrs: &[ast::Attribute], name: Symbol) -> bool {
|
|
||||||
attrs.iter().any(|attr| attr.has_name(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn first_attr_value_str_by_name(
|
|
||||||
attrs: &[ast::Attribute],
|
|
||||||
name: Symbol,
|
|
||||||
) -> Option<Symbol> {
|
|
||||||
attrs
|
|
||||||
.iter()
|
|
||||||
.find(|attr| attr.has_name(name))
|
|
||||||
.and_then(|attr| attr.value_str())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns attributes on the given statement.
|
/// Returns attributes on the given statement.
|
||||||
pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
|
pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
|
||||||
stmt.attrs()
|
stmt.attrs()
|
||||||
|
|
|
@ -2,13 +2,12 @@ use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use rustc_ast::token::TokenKind;
|
use rustc_ast::token::TokenKind;
|
||||||
use rustc_ast::{ast, ptr};
|
use rustc_ast::{ast, attr, ptr};
|
||||||
use rustc_errors::Diagnostic;
|
use rustc_errors::Diagnostic;
|
||||||
use rustc_parse::{new_parser_from_file, parser::Parser as RawParser};
|
use rustc_parse::{new_parser_from_file, parser::Parser as RawParser};
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::{sym, Span};
|
||||||
use thin_vec::ThinVec;
|
use thin_vec::ThinVec;
|
||||||
|
|
||||||
use crate::attr::first_attr_value_str_by_name;
|
|
||||||
use crate::parse::session::ParseSess;
|
use crate::parse::session::ParseSess;
|
||||||
use crate::Input;
|
use crate::Input;
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ pub(crate) enum ParserError {
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
|
pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
|
||||||
let path_sym = first_attr_value_str_by_name(attrs, sym::path)?;
|
let path_sym = attr::first_attr_value_str_by_name(attrs, sym::path)?;
|
||||||
let path_str = path_sym.as_str();
|
let path_str = path_sym.as_str();
|
||||||
|
|
||||||
// On windows, the base path might have the form
|
// On windows, the base path might have the form
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
use std::cmp::{Ord, Ordering};
|
use std::cmp::{Ord, Ordering};
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::{ast, attr};
|
||||||
use rustc_span::{symbol::sym, Span};
|
use rustc_span::{symbol::sym, Span};
|
||||||
|
|
||||||
use crate::config::{Config, GroupImportsTactic};
|
use crate::config::{Config, GroupImportsTactic};
|
||||||
|
@ -167,7 +167,7 @@ fn rewrite_reorderable_or_regroupable_items(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_macro_use_attr(item: &ast::Item) -> bool {
|
fn contains_macro_use_attr(item: &ast::Item) -> bool {
|
||||||
crate::attr::contains_name(&item.attrs, sym::macro_use)
|
attr::contains_name(&item.attrs, sym::macro_use)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Divides imports into three groups, corresponding to standard, external
|
/// Divides imports into three groups, corresponding to standard, external
|
||||||
|
|
|
@ -29,5 +29,5 @@ all:
|
||||||
--crate-type=rlib \
|
--crate-type=rlib \
|
||||||
--edition=2018 \
|
--edition=2018 \
|
||||||
c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0
|
c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0
|
||||||
$(CGREP) E0463 < $(TMPDIR)/output.txt
|
$(CGREP) E0519 < $(TMPDIR)/output.txt
|
||||||
$(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt
|
$(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt
|
||||||
|
|
|
@ -18,3 +18,9 @@ pub fn bare_fn_matches() -> &'static [SomeStruct] {
|
||||||
pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
|
pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
|
||||||
&[]
|
&[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @has doc_notable_trait_slice/fn.bare_fn_mut_no_matches.html
|
||||||
|
// @count - '//script[@id="notable-traits-data"]' 0
|
||||||
|
pub fn bare_fn_mut_no_matches() -> &'static mut [SomeStruct] {
|
||||||
|
&mut []
|
||||||
|
}
|
35
tests/rustdoc/notable-trait/notable-trait-generics.rs
Normal file
35
tests/rustdoc/notable-trait/notable-trait-generics.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#![feature(doc_notable_trait)]
|
||||||
|
|
||||||
|
// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and
|
||||||
|
// the return type has a generic type.
|
||||||
|
pub mod generic_return {
|
||||||
|
pub struct Wrapper<T>(T);
|
||||||
|
|
||||||
|
#[doc(notable_trait)]
|
||||||
|
pub trait NotableTrait {}
|
||||||
|
|
||||||
|
impl NotableTrait for Wrapper<u8> {}
|
||||||
|
|
||||||
|
// @has notable_trait_generics/generic_return/fn.returning.html
|
||||||
|
// @!has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<T>'
|
||||||
|
pub fn returning<T>() -> Wrapper<T> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notable traits SHOULD be shown when the `impl` has a generic type and the
|
||||||
|
// return type has a concrete type.
|
||||||
|
pub mod generic_impl {
|
||||||
|
pub struct Wrapper<T>(T);
|
||||||
|
|
||||||
|
#[doc(notable_trait)]
|
||||||
|
pub trait NotableTrait {}
|
||||||
|
|
||||||
|
impl<T> NotableTrait for Wrapper<T> {}
|
||||||
|
|
||||||
|
// @has notable_trait_generics/generic_impl/fn.returning.html
|
||||||
|
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<u8>'
|
||||||
|
pub fn returning() -> Wrapper<u8> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,80 +0,0 @@
|
||||||
// force-host
|
|
||||||
|
|
||||||
#![feature(rustc_private)]
|
|
||||||
|
|
||||||
extern crate rustc_driver;
|
|
||||||
extern crate rustc_hir;
|
|
||||||
extern crate rustc_lint;
|
|
||||||
extern crate rustc_span;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate rustc_session;
|
|
||||||
extern crate rustc_ast;
|
|
||||||
|
|
||||||
use rustc_ast::attr;
|
|
||||||
use rustc_driver::plugin::Registry;
|
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass};
|
|
||||||
use rustc_span::def_id::CRATE_DEF_ID;
|
|
||||||
use rustc_span::symbol::Symbol;
|
|
||||||
|
|
||||||
macro_rules! fake_lint_pass {
|
|
||||||
($struct:ident, $($attr:expr),*) => {
|
|
||||||
struct $struct;
|
|
||||||
|
|
||||||
impl LintPass for $struct {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
stringify!($struct)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LateLintPass<'_> for $struct {
|
|
||||||
fn check_crate(&mut self, cx: &LateContext) {
|
|
||||||
let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
|
||||||
let span = cx.tcx.def_span(CRATE_DEF_ID);
|
|
||||||
$(
|
|
||||||
if !cx.sess().contains_name(attrs, $attr) {
|
|
||||||
cx.lint(CRATE_NOT_OKAY, |lint| {
|
|
||||||
let msg = format!("crate is not marked with #![{}]", $attr);
|
|
||||||
lint.build(&msg).set_span(span).emit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]");
|
|
||||||
declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]");
|
|
||||||
declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]");
|
|
||||||
declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]");
|
|
||||||
declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]");
|
|
||||||
|
|
||||||
fake_lint_pass! {
|
|
||||||
PassOkay,
|
|
||||||
Symbol::intern("crate_okay")
|
|
||||||
}
|
|
||||||
|
|
||||||
fake_lint_pass! {
|
|
||||||
PassRedBlue,
|
|
||||||
Symbol::intern("crate_red"), Symbol::intern("crate_blue")
|
|
||||||
}
|
|
||||||
|
|
||||||
fake_lint_pass! {
|
|
||||||
PassGreyGreen,
|
|
||||||
Symbol::intern("crate_grey"), Symbol::intern("crate_green")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
fn __rustc_plugin_registrar(reg: &mut Registry) {
|
|
||||||
reg.lint_store.register_lints(&[
|
|
||||||
&CRATE_NOT_OKAY,
|
|
||||||
&CRATE_NOT_RED,
|
|
||||||
&CRATE_NOT_BLUE,
|
|
||||||
&CRATE_NOT_GREY,
|
|
||||||
&CRATE_NOT_GREEN,
|
|
||||||
]);
|
|
||||||
reg.lint_store.register_late_pass(|_| Box::new(PassOkay));
|
|
||||||
reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue));
|
|
||||||
reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen));
|
|
||||||
}
|
|
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
#[macro_use]
|
|
||||||
extern crate rustc_lint;
|
extern crate rustc_lint;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_session;
|
extern crate rustc_session;
|
||||||
extern crate rustc_ast;
|
extern crate rustc_ast;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
|
|
||||||
|
use rustc_ast::attr;
|
||||||
use rustc_driver::plugin::Registry;
|
use rustc_driver::plugin::Registry;
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_span::def_id::CRATE_DEF_ID;
|
use rustc_span::def_id::CRATE_DEF_ID;
|
||||||
|
@ -28,12 +28,10 @@ impl<'tcx> LateLintPass<'tcx> for Pass {
|
||||||
fn check_crate(&mut self, cx: &LateContext) {
|
fn check_crate(&mut self, cx: &LateContext) {
|
||||||
let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||||
let span = cx.tcx.def_span(CRATE_DEF_ID);
|
let span = cx.tcx.def_span(CRATE_DEF_ID);
|
||||||
if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) {
|
if !attr::contains_name(attrs, Symbol::intern("crate_okay")) {
|
||||||
cx.lint(
|
cx.lint(CRATE_NOT_OKAY, "crate is not marked with #![crate_okay]", |lint| {
|
||||||
CRATE_NOT_OKAY,
|
lint.set_span(span)
|
||||||
"crate is not marked with #![crate_okay]",
|
});
|
||||||
|lint| lint.set_span(span)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
tests/ui/associated-inherent-types/issue-109299-1.rs
Normal file
12
tests/ui/associated-inherent-types/issue-109299-1.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#![feature(inherent_associated_types, non_lifetime_binders, type_alias_impl_trait)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
struct Lexer<T>(T);
|
||||||
|
|
||||||
|
impl Lexer<i32> {
|
||||||
|
type Cursor = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
type X = impl for<T> Fn() -> Lexer<T>::Cursor; //~ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope
|
||||||
|
|
||||||
|
fn main() {}
|
15
tests/ui/associated-inherent-types/issue-109299-1.stderr
Normal file
15
tests/ui/associated-inherent-types/issue-109299-1.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope
|
||||||
|
--> $DIR/issue-109299-1.rs:10:40
|
||||||
|
|
|
||||||
|
LL | struct Lexer<T>(T);
|
||||||
|
| --------------- associated item `Cursor` not found for this struct
|
||||||
|
...
|
||||||
|
LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor;
|
||||||
|
| ^^^^^^ associated item not found in `Lexer<T>`
|
||||||
|
|
|
||||||
|
= note: the associated type was found for
|
||||||
|
- `Lexer<i32>`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0220`.
|
12
tests/ui/associated-inherent-types/issue-109299.rs
Normal file
12
tests/ui/associated-inherent-types/issue-109299.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
struct Lexer<'d>(&'d ());
|
||||||
|
|
||||||
|
impl Lexer<'d> { //~ ERROR use of undeclared lifetime name `'d`
|
||||||
|
type Cursor = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test(_: Lexer::Cursor) {}
|
||||||
|
|
||||||
|
fn main() {}
|
11
tests/ui/associated-inherent-types/issue-109299.stderr
Normal file
11
tests/ui/associated-inherent-types/issue-109299.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0261]: use of undeclared lifetime name `'d`
|
||||||
|
--> $DIR/issue-109299.rs:6:12
|
||||||
|
|
|
||||||
|
LL | impl Lexer<'d> {
|
||||||
|
| - ^^ undeclared lifetime
|
||||||
|
| |
|
||||||
|
| help: consider introducing lifetime `'d` here: `<'d>`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0261`.
|
16
tests/ui/parser/ident-recovery.rs
Normal file
16
tests/ui/parser/ident-recovery.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
fn ,comma() {
|
||||||
|
//~^ ERROR expected identifier, found `,`
|
||||||
|
struct Foo {
|
||||||
|
x: i32,,
|
||||||
|
//~^ ERROR expected identifier, found `,`
|
||||||
|
y: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break() {
|
||||||
|
//~^ ERROR expected identifier, found keyword `break`
|
||||||
|
let continue = 5;
|
||||||
|
//~^ ERROR expected identifier, found keyword `continue`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
42
tests/ui/parser/ident-recovery.stderr
Normal file
42
tests/ui/parser/ident-recovery.stderr
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
error: expected identifier, found `,`
|
||||||
|
--> $DIR/ident-recovery.rs:1:4
|
||||||
|
|
|
||||||
|
LL | fn ,comma() {
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| expected identifier
|
||||||
|
| help: remove this comma
|
||||||
|
|
||||||
|
error: expected identifier, found `,`
|
||||||
|
--> $DIR/ident-recovery.rs:4:16
|
||||||
|
|
|
||||||
|
LL | x: i32,,
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| expected identifier
|
||||||
|
| help: remove this comma
|
||||||
|
|
||||||
|
error: expected identifier, found keyword `break`
|
||||||
|
--> $DIR/ident-recovery.rs:10:4
|
||||||
|
|
|
||||||
|
LL | fn break() {
|
||||||
|
| ^^^^^ expected identifier, found keyword
|
||||||
|
|
|
||||||
|
help: escape `break` to use it as an identifier
|
||||||
|
|
|
||||||
|
LL | fn r#break() {
|
||||||
|
| ++
|
||||||
|
|
||||||
|
error: expected identifier, found keyword `continue`
|
||||||
|
--> $DIR/ident-recovery.rs:12:9
|
||||||
|
|
|
||||||
|
LL | let continue = 5;
|
||||||
|
| ^^^^^^^^ expected identifier, found keyword
|
||||||
|
|
|
||||||
|
help: escape `continue` to use it as an identifier
|
||||||
|
|
|
||||||
|
LL | let r#continue = 5;
|
||||||
|
| ++
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
|
@ -4,7 +4,11 @@ error: expected identifier, found `1main`
|
||||||
LL | fn 1main() {}
|
LL | fn 1main() {}
|
||||||
| ^^^^^ expected identifier
|
| ^^^^^ expected identifier
|
||||||
|
|
|
|
||||||
= help: identifiers cannot start with a number
|
help: identifiers cannot start with a number
|
||||||
|
--> $DIR/integer-literal-start-ident.rs:1:4
|
||||||
|
|
|
||||||
|
LL | fn 1main() {}
|
||||||
|
| ^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,19 @@
|
||||||
fn test() {
|
fn 1234test() {
|
||||||
|
//~^ ERROR expected identifier, found `1234test`
|
||||||
if let 123 = 123 { println!("yes"); }
|
if let 123 = 123 { println!("yes"); }
|
||||||
}
|
|
||||||
|
|
||||||
fn test_2() {
|
if let 2e1 = 123 {
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
let 23name = 123;
|
||||||
|
//~^ ERROR expected identifier, found `23name`
|
||||||
|
|
||||||
|
let 2x: i32 = 123;
|
||||||
|
//~^ ERROR expected identifier, found `2x`
|
||||||
|
|
||||||
let 1x = 123;
|
let 1x = 123;
|
||||||
//~^ ERROR expected identifier, found `1x`
|
//~^ ERROR expected identifier, found `1x`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_3() {
|
|
||||||
let 2x: i32 = 123;
|
|
||||||
//~^ ERROR expected identifier, found `2x`
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_4() {
|
|
||||||
if let 2e1 = 123 {
|
|
||||||
//~^ ERROR mismatched types
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_5() {
|
|
||||||
let 23name = 123;
|
|
||||||
//~^ ERROR expected identifier, found `23name`
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,35 +1,59 @@
|
||||||
error: expected identifier, found `1x`
|
error: expected identifier, found `1234test`
|
||||||
--> $DIR/issue-104088.rs:6:9
|
--> $DIR/issue-104088.rs:1:4
|
||||||
|
|
|
|
||||||
LL | let 1x = 123;
|
LL | fn 1234test() {
|
||||||
| ^^ expected identifier
|
| ^^^^^^^^ expected identifier
|
||||||
|
|
|
|
||||||
= help: identifiers cannot start with a number
|
help: identifiers cannot start with a number
|
||||||
|
--> $DIR/issue-104088.rs:1:4
|
||||||
error: expected identifier, found `2x`
|
|
||||||
--> $DIR/issue-104088.rs:11:9
|
|
||||||
|
|
|
|
||||||
LL | let 2x: i32 = 123;
|
LL | fn 1234test() {
|
||||||
| ^^ expected identifier
|
| ^^^^
|
||||||
|
|
|
||||||
= help: identifiers cannot start with a number
|
|
||||||
|
|
||||||
error: expected identifier, found `23name`
|
error: expected identifier, found `23name`
|
||||||
--> $DIR/issue-104088.rs:22:9
|
--> $DIR/issue-104088.rs:9:9
|
||||||
|
|
|
|
||||||
LL | let 23name = 123;
|
LL | let 23name = 123;
|
||||||
| ^^^^^^ expected identifier
|
| ^^^^^^ expected identifier
|
||||||
|
|
|
|
||||||
= help: identifiers cannot start with a number
|
help: identifiers cannot start with a number
|
||||||
|
--> $DIR/issue-104088.rs:9:9
|
||||||
|
|
|
||||||
|
LL | let 23name = 123;
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: expected identifier, found `2x`
|
||||||
|
--> $DIR/issue-104088.rs:12:9
|
||||||
|
|
|
||||||
|
LL | let 2x: i32 = 123;
|
||||||
|
| ^^ expected identifier
|
||||||
|
|
|
||||||
|
help: identifiers cannot start with a number
|
||||||
|
--> $DIR/issue-104088.rs:12:9
|
||||||
|
|
|
||||||
|
LL | let 2x: i32 = 123;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: expected identifier, found `1x`
|
||||||
|
--> $DIR/issue-104088.rs:15:9
|
||||||
|
|
|
||||||
|
LL | let 1x = 123;
|
||||||
|
| ^^ expected identifier
|
||||||
|
|
|
||||||
|
help: identifiers cannot start with a number
|
||||||
|
--> $DIR/issue-104088.rs:15:9
|
||||||
|
|
|
||||||
|
LL | let 1x = 123;
|
||||||
|
| ^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-104088.rs:16:12
|
--> $DIR/issue-104088.rs:5:12
|
||||||
|
|
|
|
||||||
LL | if let 2e1 = 123 {
|
LL | if let 2e1 = 123 {
|
||||||
| ^^^ --- this expression has type `{integer}`
|
| ^^^ --- this expression has type `{integer}`
|
||||||
| |
|
| |
|
||||||
| expected integer, found floating-point number
|
| expected integer, found floating-point number
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
44
tests/ui/traits/new-solver/coherence/issue-102048.rs
Normal file
44
tests/ui/traits/new-solver/coherence/issue-102048.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// This must fail coherence.
|
||||||
|
//
|
||||||
|
// Getting this to pass was fairly difficult, so here's an explanation
|
||||||
|
// of what's happening:
|
||||||
|
//
|
||||||
|
// Normalizing projections currently tries to replace them with inference variables
|
||||||
|
// while emitting a nested `Projection` obligation. This cannot be done if the projection
|
||||||
|
// has bound variables which is the case here.
|
||||||
|
//
|
||||||
|
// So the projections stay until after normalization. When unifying two projections we
|
||||||
|
// currently treat them as if they are injective, so we **incorrectly** unify their
|
||||||
|
// substs. This means that coherence for the two impls ends up unifying `?T` and `?U`
|
||||||
|
// as it tries to unify `<?T as WithAssoc1<'a>>::Assoc` with `<?U as WithAssoc1<'a>>::Assoc`.
|
||||||
|
//
|
||||||
|
// `impl1` therefore has the projection `<?T as WithAssoc2<'a>>::Assoc` and we have the
|
||||||
|
// assumption `?T: for<'a> WithAssoc2<'a, Assoc = i32>` in the `param_env`, so we normalize
|
||||||
|
// that to `i32`. We then try to unify `i32` from `impl1` with `u32` from `impl2` which fails,
|
||||||
|
// causing coherence to consider these two impls distinct.
|
||||||
|
|
||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
pub trait Trait<T> {}
|
||||||
|
|
||||||
|
pub trait WithAssoc1<'a> {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
pub trait WithAssoc2<'a> {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl 1
|
||||||
|
impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U)
|
||||||
|
where
|
||||||
|
T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>,
|
||||||
|
U: for<'a> WithAssoc2<'a>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl 2
|
||||||
|
impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where
|
||||||
|
U: for<'a> WithAssoc1<'a> //~^ ERROR conflicting implementations of trait
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
12
tests/ui/traits/new-solver/coherence/issue-102048.stderr
Normal file
12
tests/ui/traits/new-solver/coherence/issue-102048.stderr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0119]: conflicting implementations of trait `Trait<for<'a> fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)`
|
||||||
|
--> $DIR/issue-102048.rs:39:1
|
||||||
|
|
|
||||||
|
LL | impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U)
|
||||||
|
| --------------------------------------------------------------------------------------------------- first implementation here
|
||||||
|
...
|
||||||
|
LL | impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0119]: conflicting implementations of trait `OtherTrait` for type `()`
|
||||||
|
--> $DIR/coherence-conflict.rs:12:1
|
||||||
|
|
|
||||||
|
LL | impl OtherTrait for () {}
|
||||||
|
| ---------------------- first implementation here
|
||||||
|
LL | impl<T: MyTrait> OtherTrait for T {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0119]: conflicting implementations of trait `OtherTrait` for type `()`
|
error[E0119]: conflicting implementations of trait `OtherTrait` for type `()`
|
||||||
--> $DIR/coherence-conflict.rs:11:1
|
--> $DIR/coherence-conflict.rs:12:1
|
||||||
|
|
|
|
||||||
LL | impl OtherTrait for () {}
|
LL | impl OtherTrait for () {}
|
||||||
| ---------------------- first implementation here
|
| ---------------------- first implementation here
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue