1
Fork 0

Merge from rustc

This commit is contained in:
Ralf Jung 2024-05-16 10:40:15 +02:00
commit 0334bf8520
138 changed files with 2310 additions and 1057 deletions

View file

@ -2961,6 +2961,7 @@ impl Item {
| ItemKind::GlobalAsm(_) | ItemKind::GlobalAsm(_)
| ItemKind::MacCall(_) | ItemKind::MacCall(_)
| ItemKind::Delegation(_) | ItemKind::Delegation(_)
| ItemKind::DelegationMac(_)
| ItemKind::MacroDef(_) => None, | ItemKind::MacroDef(_) => None,
ItemKind::Static(_) => None, ItemKind::Static(_) => None,
ItemKind::Const(i) => Some(&i.generics), ItemKind::Const(i) => Some(&i.generics),
@ -3123,8 +3124,16 @@ pub struct Delegation {
/// Path resolution id. /// Path resolution id.
pub id: NodeId, pub id: NodeId,
pub qself: Option<P<QSelf>>, pub qself: Option<P<QSelf>>,
pub rename: Option<Ident>,
pub path: Path, pub path: Path,
pub rename: Option<Ident>,
pub body: Option<P<Block>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct DelegationMac {
pub qself: Option<P<QSelf>>,
pub prefix: Path,
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
pub body: Option<P<Block>>, pub body: Option<P<Block>>,
} }
@ -3243,10 +3252,13 @@ pub enum ItemKind {
/// A macro definition. /// A macro definition.
MacroDef(MacroDef), MacroDef(MacroDef),
/// A delegation item (`reuse`). /// A single delegation item (`reuse`).
/// ///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`. /// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>), Delegation(Box<Delegation>),
/// A list delegation item (`reuse prefix::{a, b, c}`).
/// Treated similarly to a macro call and expanded early.
DelegationMac(Box<DelegationMac>),
} }
impl ItemKind { impl ItemKind {
@ -3256,7 +3268,7 @@ impl ItemKind {
match self { match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..) Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
| Delegation(..) => "a", | Delegation(..) | DelegationMac(..) => "a",
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an", ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
} }
} }
@ -3281,6 +3293,7 @@ impl ItemKind {
ItemKind::MacroDef(..) => "macro definition", ItemKind::MacroDef(..) => "macro definition",
ItemKind::Impl { .. } => "implementation", ItemKind::Impl { .. } => "implementation",
ItemKind::Delegation(..) => "delegated function", ItemKind::Delegation(..) => "delegated function",
ItemKind::DelegationMac(..) => "delegation",
} }
} }
@ -3324,6 +3337,8 @@ pub enum AssocItemKind {
MacCall(P<MacCall>), MacCall(P<MacCall>),
/// An associated delegation item. /// An associated delegation item.
Delegation(Box<Delegation>), Delegation(Box<Delegation>),
/// An associated delegation item list.
DelegationMac(Box<DelegationMac>),
} }
impl AssocItemKind { impl AssocItemKind {
@ -3332,7 +3347,9 @@ impl AssocItemKind {
Self::Const(box ConstItem { defaultness, .. }) Self::Const(box ConstItem { defaultness, .. })
| Self::Fn(box Fn { defaultness, .. }) | Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => defaultness, | Self::Type(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final, Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
Defaultness::Final
}
} }
} }
} }
@ -3345,6 +3362,7 @@ impl From<AssocItemKind> for ItemKind {
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a), AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation), AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
AssocItemKind::DelegationMac(delegation) => ItemKind::DelegationMac(delegation),
} }
} }
} }
@ -3359,6 +3377,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind), ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a), ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
ItemKind::Delegation(d) => AssocItemKind::Delegation(d), ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
ItemKind::DelegationMac(d) => AssocItemKind::DelegationMac(d),
_ => return Err(item_kind), _ => return Err(item_kind),
}) })
} }

View file

@ -1170,6 +1170,19 @@ impl NoopVisitItemKind for ItemKind {
vis.visit_block(body); vis.visit_block(body);
} }
} }
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
vis.visit_qself(qself);
vis.visit_path(prefix);
for (ident, rename) in suffixes {
vis.visit_ident(ident);
if let Some(rename) = rename {
vis.visit_ident(rename);
}
}
if let Some(body) = body {
vis.visit_block(body);
}
}
} }
} }
} }
@ -1213,6 +1226,19 @@ impl NoopVisitItemKind for AssocItemKind {
visitor.visit_block(body); visitor.visit_block(body);
} }
} }
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
visitor.visit_qself(qself);
visitor.visit_path(prefix);
for (ident, rename) in suffixes {
visitor.visit_ident(ident);
if let Some(rename) = rename {
visitor.visit_ident(rename);
}
}
if let Some(body) = body {
visitor.visit_block(body);
}
}
} }
} }
} }

View file

@ -403,6 +403,19 @@ impl WalkItemKind for ItemKind {
visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body); visit_opt!(visitor, visit_block, body);
} }
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(prefix, item.id));
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
visit_opt!(visitor, visit_block, body);
}
} }
V::Result::output() V::Result::output()
} }
@ -815,6 +828,19 @@ impl WalkItemKind for AssocItemKind {
visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body); visit_opt!(visitor, visit_block, body);
} }
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(prefix, item.id));
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
visit_opt!(visitor, visit_block, body);
}
} }
V::Result::output() V::Result::output()
} }

View file

@ -460,8 +460,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
delegation_results.body_id, delegation_results.body_id,
) )
} }
ItemKind::MacCall(..) => { ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
panic!("`TyMac` should have been expanded by now") panic!("macros should have been expanded by now")
} }
} }
} }
@ -845,7 +845,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
(delegation_results.generics, item_kind, true) (delegation_results.generics, item_kind, true)
} }
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
panic!("macros should have been expanded by now")
}
}; };
let item = hir::TraitItem { let item = hir::TraitItem {
@ -869,7 +871,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span), has_self: self.delegation_has_self(i.id, delegation.id, i.span),
}, },
AssocItemKind::MacCall(..) => unimplemented!(), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
panic!("macros should have been expanded by now")
}
}; };
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }; let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
hir::TraitItemRef { hir::TraitItemRef {
@ -964,7 +968,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
) )
} }
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
panic!("macros should have been expanded by now")
}
}; };
let item = hir::ImplItem { let item = hir::ImplItem {
@ -993,7 +999,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
has_self: self.delegation_has_self(i.id, delegation.id, i.span), has_self: self.delegation_has_self(i.id, delegation.id, i.span),
}, },
AssocItemKind::MacCall(..) => unimplemented!(), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
panic!("macros should have been expanded by now")
}
}, },
trait_item_def_id: self trait_item_def_id: self
.resolver .resolver

View file

@ -5,6 +5,7 @@ use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::StaticItem; use ast::StaticItem;
use itertools::{Itertools, Position}; use itertools::{Itertools, Position};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::ModKind; use rustc_ast::ModKind;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
@ -374,9 +375,22 @@ impl<'a> State<'a> {
state.print_visibility(&item.vis) state.print_visibility(&item.vis)
}); });
} }
ast::ItemKind::Delegation(box delegation) => { ast::ItemKind::Delegation(deleg) => self.print_delegation(
self.print_delegation(delegation, &item.vis, &item.attrs) &item.attrs,
} &item.vis,
&deleg.qself,
&deleg.path,
None,
&deleg.body,
),
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
&item.attrs,
&item.vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
&deleg.body,
),
} }
self.ann.post(self, AnnNode::Item(item)) self.ann.post(self, AnnNode::Item(item))
} }
@ -553,31 +567,63 @@ impl<'a> State<'a> {
self.word(";"); self.word(";");
} }
} }
ast::AssocItemKind::Delegation(box delegation) => { ast::AssocItemKind::Delegation(deleg) => self.print_delegation(
self.print_delegation(delegation, vis, &item.attrs) &item.attrs,
} vis,
&deleg.qself,
&deleg.path,
None,
&deleg.body,
),
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
&item.attrs,
vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
&deleg.body,
),
} }
self.ann.post(self, AnnNode::SubItem(id)) self.ann.post(self, AnnNode::SubItem(id))
} }
pub(crate) fn print_delegation( pub(crate) fn print_delegation(
&mut self, &mut self,
delegation: &ast::Delegation,
vis: &ast::Visibility,
attrs: &[ast::Attribute], attrs: &[ast::Attribute],
vis: &ast::Visibility,
qself: &Option<P<ast::QSelf>>,
path: &ast::Path,
suffixes: Option<&[(Ident, Option<Ident>)]>,
body: &Option<P<ast::Block>>,
) { ) {
if delegation.body.is_some() { if body.is_some() {
self.head(""); self.head("");
} }
self.print_visibility(vis); self.print_visibility(vis);
self.word_space("reuse"); self.word_nbsp("reuse");
if let Some(qself) = &delegation.qself { if let Some(qself) = qself {
self.print_qpath(&delegation.path, qself, false); self.print_qpath(path, qself, false);
} else { } else {
self.print_path(&delegation.path, false, 0); self.print_path(path, false, 0);
} }
if let Some(body) = &delegation.body { if let Some(suffixes) = suffixes {
self.word("::");
self.word("{");
for (i, (ident, rename)) in suffixes.iter().enumerate() {
self.print_ident(*ident);
if let Some(rename) = rename {
self.nbsp();
self.word_nbsp("as");
self.print_ident(*rename);
}
if i != suffixes.len() - 1 {
self.word_space(",");
}
}
self.word("}");
}
if let Some(body) = body {
self.nbsp(); self.nbsp();
self.print_block_with_attrs(body, attrs); self.print_block_with_attrs(body, attrs);
} else { } else {

View file

@ -207,13 +207,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
let cond_bitmap = coverage_context let cond_bitmap = coverage_context
.try_get_mcdc_condition_bitmap(&instance, decision_depth) .try_get_mcdc_condition_bitmap(&instance, decision_depth)
.expect("mcdc cond bitmap should have been allocated for merging into the global bitmap"); .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
let bitmap_bytes = bx.tcx().coverage_ids_info(instance.def).mcdc_bitmap_bytes; let bitmap_bytes = function_coverage_info.mcdc_bitmap_bytes;
assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range"); assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range");
assert!(
bitmap_bytes <= function_coverage_info.mcdc_bitmap_bytes,
"bitmap length disagreement: query says {bitmap_bytes} but function info only has {}",
function_coverage_info.mcdc_bitmap_bytes
);
let fn_name = bx.get_pgo_func_name_var(instance); let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_coverage_info.function_source_hash); let hash = bx.const_u64(function_coverage_info.function_source_hash);

View file

@ -896,7 +896,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
style: SuggestionStyle, style: SuggestionStyle,
) -> &mut Self { ) -> &mut Self {
suggestion.sort_unstable(); suggestion.sort_unstable();
suggestion.dedup(); suggestion.dedup_by(|(s1, m1), (s2, m2)| s1.source_equal(*s2) && m1 == m2);
let parts = suggestion let parts = suggestion
.into_iter() .into_iter()

View file

@ -106,6 +106,12 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTrait
} }
} }
impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> {
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
format!("{self:?}").into_diag_arg()
}
}
into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
impl IntoDiagArg for bool { impl IntoDiagArg for bool {

View file

@ -30,6 +30,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
.label = duplicate binding .label = duplicate binding
.label2 = previous binding .label2 = previous binding
expand_empty_delegation_list =
empty list delegation is not supported
expand_expected_paren_or_brace = expand_expected_paren_or_brace =
expected `(` or `{"{"}`, found `{$token}` expected `(` or `{"{"}`, found `{$token}`

View file

@ -433,3 +433,10 @@ pub struct ExpectedParenOrBrace<'a> {
pub span: Span, pub span: Span,
pub token: Cow<'a, str>, pub token: Cow<'a, str>,
} }
#[derive(Diagnostic)]
#[diag(expand_empty_delegation_list)]
pub(crate) struct EmptyDelegationList {
#[primary_span]
pub span: Span,
}

View file

@ -1,8 +1,8 @@
use crate::base::*; use crate::base::*;
use crate::config::StripUnconfigured; use crate::config::StripUnconfigured;
use crate::errors::{ use crate::errors::{
IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
UnsupportedKeyValue, WrongFragmentKind, RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
}; };
use crate::mbe::diagnostics::annotate_err_with_kind; use crate::mbe::diagnostics::annotate_err_with_kind;
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
@ -1041,6 +1041,7 @@ enum AddSemicolon {
trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
type OutputTy = SmallVec<[Self; 1]>; type OutputTy = SmallVec<[Self; 1]>;
type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec; type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
type ItemKind = ItemKind;
const KIND: AstFragmentKind; const KIND: AstFragmentKind;
fn to_annotatable(self) -> Annotatable; fn to_annotatable(self) -> Annotatable;
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy; fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
@ -1059,6 +1060,18 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) { fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
unreachable!() unreachable!()
} }
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
None
}
fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
unreachable!()
}
fn from_item(_item: ast::Item<Self::ItemKind>) -> Self {
unreachable!()
}
fn flatten_outputs(_outputs: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
unreachable!()
}
fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {} fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) { fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
} }
@ -1106,6 +1119,21 @@ impl InvocationCollectorNode for P<ast::Item> {
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.kind {
ItemKind::DelegationMac(deleg) => Some((deleg, self)),
_ => None,
}
}
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
ItemKind::Delegation(deleg)
}
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
P(item)
}
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
items.flatten().collect()
}
fn wrap_flat_map_node_noop_flat_map( fn wrap_flat_map_node_noop_flat_map(
mut node: Self, mut node: Self,
collector: &mut InvocationCollector<'_, '_>, collector: &mut InvocationCollector<'_, '_>,
@ -1214,6 +1242,7 @@ impl InvocationCollectorNode for P<ast::Item> {
struct TraitItemTag; struct TraitItemTag;
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> { impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
type ItemKind = AssocItemKind;
const KIND: AstFragmentKind = AstFragmentKind::TraitItems; const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
fn to_annotatable(self) -> Annotatable { fn to_annotatable(self) -> Annotatable {
Annotatable::TraitItem(self.wrapped) Annotatable::TraitItem(self.wrapped)
@ -1234,11 +1263,27 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.wrapped.kind {
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
_ => None,
}
}
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
AssocItemKind::Delegation(deleg)
}
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
AstNodeWrapper::new(P(item), TraitItemTag)
}
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
items.flatten().collect()
}
} }
struct ImplItemTag; struct ImplItemTag;
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> { impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
type ItemKind = AssocItemKind;
const KIND: AstFragmentKind = AstFragmentKind::ImplItems; const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
fn to_annotatable(self) -> Annotatable { fn to_annotatable(self) -> Annotatable {
Annotatable::ImplItem(self.wrapped) Annotatable::ImplItem(self.wrapped)
@ -1259,6 +1304,21 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.wrapped.kind {
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
_ => None,
}
}
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
AssocItemKind::Delegation(deleg)
}
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
AstNodeWrapper::new(P(item), ImplItemTag)
}
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
items.flatten().collect()
}
} }
impl InvocationCollectorNode for P<ast::ForeignItem> { impl InvocationCollectorNode for P<ast::ForeignItem> {
@ -1420,6 +1480,24 @@ impl InvocationCollectorNode for ast::Stmt {
}; };
(mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No }) (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
} }
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.kind {
StmtKind::Item(item) => match &item.kind {
ItemKind::DelegationMac(deleg) => Some((deleg, item)),
_ => None,
},
_ => None,
}
}
fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
ItemKind::Delegation(deleg)
}
fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) }
}
fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
items.flatten().collect()
}
fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) { fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
// If this is a macro invocation with a semicolon, then apply that // If this is a macro invocation with a semicolon, then apply that
// semicolon to the final statement produced by expansion. // semicolon to the final statement produced by expansion.
@ -1818,6 +1896,40 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
Node::post_flat_map_node_collect_bang(&mut res, add_semicolon); Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
res res
} }
None if let Some((deleg, item)) = node.delegation_list() => {
if deleg.suffixes.is_empty() {
// Report an error for now, to avoid keeping stem for resolution and
// stability checks.
self.cx.dcx().emit_err(EmptyDelegationList { span: item.span });
}
Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| {
let mut path = deleg.prefix.clone();
path.segments.push(ast::PathSegment {
ident,
id: ast::DUMMY_NODE_ID,
args: None,
});
let mut item = Node::from_item(ast::Item {
attrs: item.attrs.clone(),
id: ast::DUMMY_NODE_ID,
span: ident.span,
vis: item.vis.clone(),
ident: rename.unwrap_or(ident),
kind: Node::delegation_item_kind(Box::new(ast::Delegation {
id: ast::DUMMY_NODE_ID,
qself: deleg.qself.clone(),
path,
rename,
body: deleg.body.clone(),
})),
tokens: None,
});
assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
}))
}
None => { None => {
match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| { match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this)) assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this))
@ -1866,6 +1978,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
self.collect_bang(mac, Node::KIND).make_ast::<Node>() self.collect_bang(mac, Node::KIND).make_ast::<Node>()
}) })
} }
None if node.delegation_list().is_some() => unreachable!(),
None => { None => {
assign_id!(self, node.node_id_mut(), || node.noop_visit(self)) assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
} }

View file

@ -23,7 +23,7 @@ pub(crate) enum MetaVarExpr {
/// The length of the repetition at a particular depth, where 0 is the inner-most /// The length of the repetition at a particular depth, where 0 is the inner-most
/// repetition. The `usize` is the depth. /// repetition. The `usize` is the depth.
Length(usize), Len(usize),
} }
impl MetaVarExpr { impl MetaVarExpr {
@ -48,13 +48,13 @@ impl MetaVarExpr {
MetaVarExpr::Ignore(parse_ident(&mut iter, psess, ident.span)?) MetaVarExpr::Ignore(parse_ident(&mut iter, psess, ident.span)?)
} }
"index" => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?), "index" => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?),
"length" => MetaVarExpr::Length(parse_depth(&mut iter, psess, ident.span)?), "len" => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?),
_ => { _ => {
let err_msg = "unrecognized meta-variable expression"; let err_msg = "unrecognized meta-variable expression";
let mut err = psess.dcx.struct_span_err(ident.span, err_msg); let mut err = psess.dcx.struct_span_err(ident.span, err_msg);
err.span_suggestion( err.span_suggestion(
ident.span, ident.span,
"supported expressions are count, ignore, index and length", "supported expressions are count, ignore, index and len",
"", "",
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@ -68,7 +68,7 @@ impl MetaVarExpr {
pub(crate) fn ident(&self) -> Option<Ident> { pub(crate) fn ident(&self) -> Option<Ident> {
match *self { match *self {
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident), MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None, MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None,
} }
} }
} }
@ -111,7 +111,7 @@ fn parse_count<'psess>(
Ok(MetaVarExpr::Count(ident, depth)) Ok(MetaVarExpr::Count(ident, depth))
} }
/// Parses the depth used by index(depth) and length(depth). /// Parses the depth used by index(depth) and len(depth).
fn parse_depth<'psess>( fn parse_depth<'psess>(
iter: &mut RefTokenTreeCursor<'_>, iter: &mut RefTokenTreeCursor<'_>,
psess: &'psess ParseSess, psess: &'psess ParseSess,

View file

@ -357,7 +357,7 @@ fn parse_sep_and_kleene_op<'a>(
// `$$` or a meta-variable is the lhs of a macro but shouldn't. // `$$` or a meta-variable is the lhs of a macro but shouldn't.
// //
// For example, `macro_rules! foo { ( ${length()} ) => {} }` // For example, `macro_rules! foo { ( ${len()} ) => {} }`
fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &Session, token: &Token) { fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &Session, token: &Token) {
sess.dcx() sess.dcx()
.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token))); .span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));

View file

@ -685,14 +685,14 @@ fn transcribe_metavar_expr<'a>(
} }
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")), None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
}, },
MetaVarExpr::Length(depth) => match repeats.iter().nth_back(depth) { MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) {
Some((_, length)) => { Some((_, length)) => {
result.push(TokenTree::token_alone( result.push(TokenTree::token_alone(
TokenKind::lit(token::Integer, sym::integer(*length), None), TokenKind::lit(token::Integer, sym::integer(*length), None),
visited_span(), visited_span(),
)); ));
} }
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "length")), None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "len")),
}, },
} }
Ok(()) Ok(())

View file

@ -938,14 +938,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
pub fn get_conversion_methods( pub fn get_conversion_methods_for_diagnostic(
&self, &self,
span: Span, span: Span,
expected: Ty<'tcx>, expected: Ty<'tcx>,
checked_ty: Ty<'tcx>, checked_ty: Ty<'tcx>,
hir_id: hir::HirId, hir_id: hir::HirId,
) -> Vec<AssocItem> { ) -> Vec<AssocItem> {
let methods = self.probe_for_return_type( let methods = self.probe_for_return_type_for_diagnostic(
span, span,
probe::Mode::MethodCall, probe::Mode::MethodCall,
expected, expected,

View file

@ -2414,7 +2414,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let guar = if field.name == kw::Empty { let guar = if field.name == kw::Empty {
self.dcx().span_delayed_bug(field.span, "field name with no name") self.dcx().span_delayed_bug(field.span, "field name with no name")
} else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) { } else if self.method_exists_for_diagnostic(
field,
base_ty,
expr.hir_id,
expected.only_has_type(self),
) {
self.ban_take_value_of_method(expr, base_ty, field) self.ban_take_value_of_method(expr, base_ty, field)
} else if !base_ty.is_primitive_ty() { } else if !base_ty.is_primitive_ty() {
self.ban_nonexisting_field(field, base, expr, base_ty) self.ban_nonexisting_field(field, base, expr, base_ty)
@ -2600,7 +2605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut err = self.private_field_err(field, base_did); let mut err = self.private_field_err(field, base_did);
// Also check if an accessible method exists, which is often what is meant. // Also check if an accessible method exists, which is often what is meant.
if self.method_exists(field, expr_t, expr.hir_id, return_ty) if self.method_exists_for_diagnostic(field, expr_t, expr.hir_id, return_ty)
&& !self.expr_in_place(expr.hir_id) && !self.expr_in_place(expr.hir_id)
{ {
self.suggest_method_call( self.suggest_method_call(

View file

@ -18,12 +18,12 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, Res}; use rustc_hir::def::{CtorOf, Res};
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::{HirId, PatKind}; use rustc_hir::{HirId, PatKind};
use rustc_middle::{bug, span_bug};
use rustc_middle::hir::place::ProjectionKind; use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::FakeReadCause; use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _,
}; };
use rustc_middle::{bug, span_bug};
use rustc_span::{ErrorGuaranteed, Span}; use rustc_span::{ErrorGuaranteed, Span};
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
@ -1181,6 +1181,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty); debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
return Ok(*first_ty); return Ok(*first_ty);
} }
} else if let PatKind::Ref(subpat, _) = pat.kind
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
{
return self.pat_ty_adjusted(subpat);
} }
self.pat_ty_unadjusted(pat) self.pat_ty_unadjusted(pat)
@ -1712,6 +1716,12 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
self.cat_pattern(place_with_id, subpat, op)?; self.cat_pattern(place_with_id, subpat, op)?;
} }
PatKind::Ref(subpat, _)
if self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) =>
{
self.cat_pattern(place_with_id, subpat, op)?;
}
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => { PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
// box p1, &p1, &mut p1. we can ignore the mutability of // box p1, &p1, &mut p1. we can ignore the mutability of
// PatKind::Ref since that information is already contained // PatKind::Ref since that information is already contained

View file

@ -290,7 +290,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) -> bool { ) -> bool {
let expr = expr.peel_blocks(); let expr = expr.peel_blocks();
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); let methods =
self.get_conversion_methods_for_diagnostic(expr.span, expected, found, expr.hir_id);
if let Some((suggestion, msg, applicability, verbose, annotation)) = if let Some((suggestion, msg, applicability, verbose, annotation)) =
self.suggest_deref_or_ref(expr, found, expected) self.suggest_deref_or_ref(expr, found, expected)

View file

@ -91,7 +91,7 @@ pub enum CandidateSource {
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Determines whether the type `self_ty` supports a visible method named `method_name` or not. /// Determines whether the type `self_ty` supports a visible method named `method_name` or not.
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
pub fn method_exists( pub fn method_exists_for_diagnostic(
&self, &self,
method_name: Ident, method_name: Ident,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
probe::Mode::MethodCall, probe::Mode::MethodCall,
method_name, method_name,
return_type, return_type,
IsSuggestion(false), IsSuggestion(true),
self_ty, self_ty,
call_expr_id, call_expr_id,
ProbeScope::TraitsInScope, ProbeScope::TraitsInScope,

View file

@ -90,6 +90,11 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
>, >,
scope_expr_id: HirId, scope_expr_id: HirId,
/// Is this probe being done for a diagnostic? This will skip some error reporting
/// machinery, since we don't particularly care about, for example, similarly named
/// candidates if we're *reporting* similarly named candidates.
is_suggestion: IsSuggestion,
} }
impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
@ -220,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// would use to decide if a method is a plausible fit for /// would use to decide if a method is a plausible fit for
/// ambiguity purposes). /// ambiguity purposes).
#[instrument(level = "debug", skip(self, candidate_filter))] #[instrument(level = "debug", skip(self, candidate_filter))]
pub fn probe_for_return_type( pub fn probe_for_return_type_for_diagnostic(
&self, &self,
span: Span, span: Span,
mode: Mode, mode: Mode,
@ -459,6 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&orig_values, &orig_values,
steps.steps, steps.steps,
scope_expr_id, scope_expr_id,
is_suggestion,
); );
probe_cx.assemble_inherent_candidates(); probe_cx.assemble_inherent_candidates();
@ -553,6 +559,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
orig_steps_var_values: &'a OriginalQueryValues<'tcx>, orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
steps: &'tcx [CandidateStep<'tcx>], steps: &'tcx [CandidateStep<'tcx>],
scope_expr_id: HirId, scope_expr_id: HirId,
is_suggestion: IsSuggestion,
) -> ProbeContext<'a, 'tcx> { ) -> ProbeContext<'a, 'tcx> {
ProbeContext { ProbeContext {
fcx, fcx,
@ -570,6 +577,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
static_candidates: RefCell::new(Vec::new()), static_candidates: RefCell::new(Vec::new()),
unsatisfied_predicates: RefCell::new(Vec::new()), unsatisfied_predicates: RefCell::new(Vec::new()),
scope_expr_id, scope_expr_id,
is_suggestion,
} }
} }
@ -944,6 +952,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
return r; return r;
} }
// If it's a `lookup_probe_for_diagnostic`, then quit early. No need to
// probe for other candidates.
if self.is_suggestion.0 {
return Err(MethodError::NoMatch(NoMatchData {
static_candidates: vec![],
unsatisfied_predicates: vec![],
out_of_scope_traits: vec![],
similar_candidate: None,
mode: self.mode,
}));
}
debug!("pick: actual search failed, assemble diagnostics"); debug!("pick: actual search failed, assemble diagnostics");
let static_candidates = std::mem::take(self.static_candidates.get_mut()); let static_candidates = std::mem::take(self.static_candidates.get_mut());
@ -1631,6 +1651,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.orig_steps_var_values, self.orig_steps_var_values,
self.steps, self.steps,
self.scope_expr_id, self.scope_expr_id,
IsSuggestion(true),
); );
pcx.allow_similar_names = true; pcx.allow_similar_names = true;
pcx.assemble_inherent_candidates(); pcx.assemble_inherent_candidates();

View file

@ -1143,7 +1143,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
let label_span_not_found = |err: &mut Diag<'_>| { let mut find_candidate_for_method = false;
let mut label_span_not_found = |err: &mut Diag<'_>| {
if unsatisfied_predicates.is_empty() { if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
let is_string_or_ref_str = match rcvr_ty.kind() { let is_string_or_ref_str = match rcvr_ty.kind() {
@ -1219,6 +1221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.note(format!( err.note(format!(
"the {item_kind} was found for\n{type_candidates}{additional_types}" "the {item_kind} was found for\n{type_candidates}{additional_types}"
)); ));
find_candidate_for_method = mode == Mode::MethodCall;
} }
} }
} else { } else {
@ -1371,9 +1374,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
} }
// If an appropriate error source is not found, check method chain for possible candiates
if unsatisfied_predicates.is_empty() if !find_candidate_for_method {
&& let Mode::MethodCall = mode self.lookup_segments_chain_for_no_match_method(
&mut err,
item_name,
item_kind,
source,
no_match_data,
);
}
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
Some(err)
}
/// If an appropriate error source is not found, check method chain for possible candidates
fn lookup_segments_chain_for_no_match_method(
&self,
err: &mut Diag<'_>,
item_name: Ident,
item_kind: &str,
source: SelfSource<'tcx>,
no_match_data: &NoMatchData<'tcx>,
) {
if no_match_data.unsatisfied_predicates.is_empty()
&& let Mode::MethodCall = no_match_data.mode
&& let SelfSource::MethodCall(mut source_expr) = source && let SelfSource::MethodCall(mut source_expr) = source
{ {
let mut stack_methods = vec![]; let mut stack_methods = vec![];
@ -1394,6 +1420,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.unwrap_or(Ty::new_misc_error(self.tcx)), .unwrap_or(Ty::new_misc_error(self.tcx)),
); );
// FIXME: `probe_for_name_many` searches for methods in inherent implementations,
// so it may return a candidate that doesn't belong to this `revr_ty`. We need to
// check whether the instantiated type matches the received one.
for _matched_method in self.probe_for_name_many( for _matched_method in self.probe_for_name_many(
Mode::MethodCall, Mode::MethodCall,
item_name, item_name,
@ -1416,8 +1445,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
} }
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
Some(err)
} }
fn find_likely_intended_associated_item( fn find_likely_intended_associated_item(
@ -2814,7 +2841,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(output_ty) => self.resolve_vars_if_possible(output_ty), Some(output_ty) => self.resolve_vars_if_possible(output_ty),
_ => return, _ => return,
}; };
let method_exists = self.method_exists(item_name, output_ty, call.hir_id, return_type); let method_exists =
self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type);
debug!("suggest_await_before_method: is_method_exist={}", method_exists); debug!("suggest_await_before_method: is_method_exist={}", method_exists);
if method_exists { if method_exists {
err.span_suggestion_verbose( err.span_suggestion_verbose(

View file

@ -347,5 +347,13 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
"reduce the glob import's visibility or increase visibility of imported items", "reduce the glob import's visibility or increase visibility of imported items",
); );
} }
BuiltinLintDiag::MaybeTypo { span, name } => {
diag.span_suggestion_verbose(
span,
"an attribute with a similar name exists",
name,
Applicability::MachineApplicable,
);
}
} }
} }

View file

@ -663,6 +663,10 @@ pub enum BuiltinLintDiag {
span: Span, span: Span,
max_vis: String, max_vis: String,
}, },
MaybeTypo {
span: Span,
name: Symbol,
},
} }
/// Lints that are buffered up early on in the `Session` before the /// Lints that are buffered up early on in the `Session` before the

View file

@ -129,17 +129,11 @@ pub enum CoverageKind {
/// Marks the point in MIR control flow represented by a evaluated condition. /// Marks the point in MIR control flow represented by a evaluated condition.
/// ///
/// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR. /// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR.
///
/// If this statement does not survive MIR optimizations, the condition would never be
/// taken as evaluated.
CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 }, CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 },
/// Marks the point in MIR control flow represented by a evaluated decision. /// Marks the point in MIR control flow represented by a evaluated decision.
/// ///
/// This is eventually lowered to `llvm.instrprof.mcdc.tvbitmap.update` in LLVM IR. /// This is eventually lowered to `llvm.instrprof.mcdc.tvbitmap.update` in LLVM IR.
///
/// If this statement does not survive MIR optimizations, the decision would never be
/// taken as evaluated.
TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 }, TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 },
} }

View file

@ -362,8 +362,4 @@ pub struct CoverageIdsInfo {
/// InstrumentCoverage MIR pass, if the highest-numbered counter increments /// InstrumentCoverage MIR pass, if the highest-numbered counter increments
/// were removed by MIR optimizations. /// were removed by MIR optimizations.
pub max_counter_id: mir::coverage::CounterId, pub max_counter_id: mir::coverage::CounterId,
/// Coverage codegen for mcdc needs to know the size of the global bitmap so that it can
/// set the `bytemap-bytes` argument of the `llvm.instrprof.mcdc.tvbitmap.update` intrinsic.
pub mcdc_bitmap_bytes: u32,
} }

View file

@ -1480,13 +1480,17 @@ pub enum BinOp {
BitOr, BitOr,
/// The `<<` operator (shift left) /// The `<<` operator (shift left)
/// ///
/// The offset is truncated to the size of the first operand and made unsigned before shifting. /// The offset is (uniquely) determined as follows:
/// - it is "equal modulo LHS::BITS" to the RHS
/// - it is in the range `0..LHS::BITS`
Shl, Shl,
/// Like `Shl`, but is UB if the RHS >= LHS::BITS or RHS < 0 /// Like `Shl`, but is UB if the RHS >= LHS::BITS or RHS < 0
ShlUnchecked, ShlUnchecked,
/// The `>>` operator (shift right) /// The `>>` operator (shift right)
/// ///
/// The offset is truncated to the size of the first operand and made unsigned before shifting. /// The offset is (uniquely) determined as follows:
/// - it is "equal modulo LHS::BITS" to the RHS
/// - it is in the range `0..LHS::BITS`
/// ///
/// This is an arithmetic shift if the LHS is signed /// This is an arithmetic shift if the LHS is signed
/// and a logical shift if the LHS is unsigned. /// and a logical shift if the LHS is unsigned.

View file

@ -153,6 +153,8 @@ pub enum ProbeKind<'tcx> {
/// do a probe to find out what projection type(s) may be used to prove that /// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds. /// the source type upholds all of the target type's object bounds.
UpcastProjectionCompatibility, UpcastProjectionCompatibility,
/// Looking for param-env candidates that satisfy the trait ref for a projection.
ShadowedEnvProbing,
/// Try to unify an opaque type with an existing key in the storage. /// Try to unify an opaque type with an existing key in the storage.
OpaqueTypeStorageLookup { result: QueryResult<'tcx> }, OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
} }

View file

@ -118,6 +118,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
ProbeKind::TraitCandidate { source, result } => { ProbeKind::TraitCandidate { source, result } => {
write!(self.f, "CANDIDATE {source:?}: {result:?}") write!(self.f, "CANDIDATE {source:?}: {result:?}")
} }
ProbeKind::ShadowedEnvProbing => {
write!(self.f, "PROBING FOR IMPLS SHADOWED BY PARAM-ENV CANDIDATE:")
}
}?; }?;
self.nested(|this| { self.nested(|this| {

View file

@ -7,8 +7,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_type_ir::ConstKind as IrConstKind; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
use rustc_type_ir::{TypeFlags, WithCachedTypeInfo};
mod int; mod int;
mod kind; mod kind;
@ -20,7 +19,8 @@ use rustc_span::Span;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
pub use valtree::*; pub use valtree::*;
pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>; pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); rustc_data_structures::static_assert_size!(ConstKind<'_>, 32);
@ -184,6 +184,14 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
Const::new_bound(tcx, debruijn, var, ty) Const::new_bound(tcx, debruijn, var, ty)
} }
fn new_unevaluated(
interner: TyCtxt<'tcx>,
uv: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
) -> Self {
Const::new_unevaluated(interner, uv, ty)
}
fn ty(self) -> Ty<'tcx> { fn ty(self) -> Ty<'tcx> {
self.ty() self.ty()
} }

View file

@ -1,30 +1,15 @@
use super::Const; use super::Const;
use crate::mir; use crate::mir;
use crate::ty::abstract_const::CastKind; use crate::ty::abstract_const::CastKind;
use crate::ty::GenericArgsRef;
use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt}; use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
use rustc_hir::def_id::DefId; use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
/// An unevaluated (potentially generic) constant used in the type-system. #[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)] impl<'tcx> ty::UnevaluatedConst<'tcx> {
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct UnevaluatedConst<'tcx> {
pub def: DefId,
pub args: GenericArgsRef<'tcx>,
}
impl rustc_errors::IntoDiagArg for UnevaluatedConst<'_> {
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
format!("{self:?}").into_diag_arg()
}
}
impl<'tcx> UnevaluatedConst<'tcx> {
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
/// hurts performance. /// hurts performance.
#[inline] #[inline]
pub(crate) fn prepare_for_eval( fn prepare_for_eval(
self, self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
@ -55,13 +40,6 @@ impl<'tcx> UnevaluatedConst<'tcx> {
} }
} }
impl<'tcx> UnevaluatedConst<'tcx> {
#[inline]
pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
UnevaluatedConst { def, args }
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
pub enum Expr<'tcx> { pub enum Expr<'tcx> {

View file

@ -76,6 +76,7 @@ use rustc_type_ir::TyKind::*;
use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::WithCachedTypeInfo;
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
use std::assert_matches::assert_matches;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
@ -91,67 +92,124 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>; type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
type AdtDef = ty::AdtDef<'tcx>; type AdtDef = ty::AdtDef<'tcx>;
type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>;
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
type GenericArg = ty::GenericArg<'tcx>; type GenericArg = ty::GenericArg<'tcx>;
type Term = ty::Term<'tcx>;
type Term = ty::Term<'tcx>;
type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>; type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
type BoundVars = &'tcx List<ty::BoundVariableKind>; type BoundVars = &'tcx List<ty::BoundVariableKind>;
type BoundVar = ty::BoundVariableKind; type BoundVar = ty::BoundVariableKind;
type CanonicalVars = CanonicalVarInfos<'tcx>;
type CanonicalVars = CanonicalVarInfos<'tcx>;
type Ty = Ty<'tcx>; type Ty = Ty<'tcx>;
type Tys = &'tcx List<Ty<'tcx>>; type Tys = &'tcx List<Ty<'tcx>>;
type AliasTy = ty::AliasTy<'tcx>;
type ParamTy = ParamTy; type ParamTy = ParamTy;
type BoundTy = ty::BoundTy; type BoundTy = ty::BoundTy;
type PlaceholderTy = ty::PlaceholderType; type PlaceholderTy = ty::PlaceholderType;
type ErrorGuaranteed = ErrorGuaranteed;
type ErrorGuaranteed = ErrorGuaranteed;
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>; type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
type PolyFnSig = PolyFnSig<'tcx>; type PolyFnSig = PolyFnSig<'tcx>;
type AllocId = crate::mir::interpret::AllocId; type AllocId = crate::mir::interpret::AllocId;
type Pat = Pattern<'tcx>;
type Pat = Pattern<'tcx>;
type Const = ty::Const<'tcx>; type Const = ty::Const<'tcx>;
type AliasConst = ty::UnevaluatedConst<'tcx>; type AliasConst = ty::UnevaluatedConst<'tcx>;
type PlaceholderConst = ty::PlaceholderConst; type PlaceholderConst = ty::PlaceholderConst;
type ParamConst = ty::ParamConst; type ParamConst = ty::ParamConst;
type BoundConst = ty::BoundVar; type BoundConst = ty::BoundVar;
type ValueConst = ty::ValTree<'tcx>; type ValueConst = ty::ValTree<'tcx>;
type ExprConst = ty::Expr<'tcx>;
type ExprConst = ty::Expr<'tcx>;
type Region = Region<'tcx>; type Region = Region<'tcx>;
type EarlyParamRegion = ty::EarlyParamRegion; type EarlyParamRegion = ty::EarlyParamRegion;
type LateParamRegion = ty::LateParamRegion; type LateParamRegion = ty::LateParamRegion;
type BoundRegion = ty::BoundRegion; type BoundRegion = ty::BoundRegion;
type InferRegion = ty::RegionVid; type InferRegion = ty::RegionVid;
type PlaceholderRegion = ty::PlaceholderRegion;
type PlaceholderRegion = ty::PlaceholderRegion;
type Predicate = Predicate<'tcx>; type Predicate = Predicate<'tcx>;
type TraitPredicate = ty::TraitPredicate<'tcx>; type TraitPredicate = ty::TraitPredicate<'tcx>;
type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>; type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>; type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
type ProjectionPredicate = ty::ProjectionPredicate<'tcx>; type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
type AliasTerm = ty::AliasTerm<'tcx>;
type NormalizesTo = ty::NormalizesTo<'tcx>; type NormalizesTo = ty::NormalizesTo<'tcx>;
type SubtypePredicate = ty::SubtypePredicate<'tcx>; type SubtypePredicate = ty::SubtypePredicate<'tcx>;
type CoercePredicate = ty::CoercePredicate<'tcx>; type CoercePredicate = ty::CoercePredicate<'tcx>;
type ClosureKind = ty::ClosureKind; type ClosureKind = ty::ClosureKind;
type Clauses = ty::Clauses<'tcx>;
type Clauses = ty::Clauses<'tcx>;
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars { fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
self.mk_canonical_var_infos(infos) self.mk_canonical_var_infos(infos)
} }
type GenericsOf = &'tcx ty::Generics; type GenericsOf = &'tcx ty::Generics;
fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics { fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
self.generics_of(def_id) self.generics_of(def_id)
} }
fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> {
self.type_of(def_id).instantiate(self, args)
}
fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
match self.def_kind(alias.def_id) {
DefKind::AssocTy => {
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
{
ty::Inherent
} else {
ty::Projection
}
}
DefKind::OpaqueTy => ty::Opaque,
DefKind::TyAlias => ty::Weak,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
}
fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind {
match self.def_kind(alias.def_id) {
DefKind::AssocTy => {
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
{
ty::AliasTermKind::InherentTy
} else {
ty::AliasTermKind::ProjectionTy
}
}
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
DefKind::TyAlias => ty::AliasTermKind::WeakTy,
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
}
fn trait_ref_and_own_args_for_alias(
self,
def_id: Self::DefId,
args: Self::GenericArgs,
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
let trait_def_id = self.parent(def_id);
assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
let trait_generics = self.generics_of(trait_def_id);
(
ty::TraitRef::new(self, trait_def_id, args.truncate_to(self, trait_generics)),
&args[trait_generics.count()..],
)
}
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
self.mk_args(args) self.mk_args(args)
} }
fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs {
self.mk_args_from_iter(args)
}
fn check_and_mk_args( fn check_and_mk_args(
self, self,
def_id: DefId, def_id: DefId,

View file

@ -96,9 +96,9 @@ pub use self::list::{List, ListWithCachedTypeInfo};
pub use self::parameterized::ParameterizedOverTcx; pub use self::parameterized::ParameterizedOverTcx;
pub use self::pattern::{Pattern, PatternKind}; pub use self::pattern::{Pattern, PatternKind};
pub use self::predicate::{ pub use self::predicate::{
Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt, AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate, ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo,
PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
@ -110,11 +110,11 @@ pub use self::region::{
}; };
pub use self::rvalue_scopes::RvalueScopes; pub use self::rvalue_scopes::RvalueScopes;
pub use self::sty::{ pub use self::sty::{
AliasTerm, AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
CoroutineClosureArgs, CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs,
InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
UpvarArgs, VarianceDiagInfo, VarianceDiagInfo,
}; };
pub use self::trait_def::TraitDef; pub use self::trait_def::TraitDef;
pub use self::typeck_results::{ pub use self::typeck_results::{

View file

@ -13,6 +13,7 @@ use crate::ty::{
}; };
pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>; pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
pub type AliasTerm<'tcx> = ir::AliasTerm<TyCtxt<'tcx>>;
pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>; pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>;
pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>; pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>;
pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>; pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;

View file

@ -3038,6 +3038,33 @@ define_print! {
p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
} }
ty::AliasTy<'tcx> {
let alias_term: ty::AliasTerm<'tcx> = (*self).into();
p!(print(alias_term))
}
ty::AliasTerm<'tcx> {
match self.kind(cx.tcx()) {
ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
ty::AliasTermKind::ProjectionTy
| ty::AliasTermKind::WeakTy
| ty::AliasTermKind::OpaqueTy
| ty::AliasTermKind::UnevaluatedConst
| ty::AliasTermKind::ProjectionConst => {
// If we're printing verbosely, or don't want to invoke queries
// (`is_impl_trait_in_trait`), then fall back to printing the def path.
// This is likely what you want if you're debugging the compiler anyways.
if !(cx.should_print_verbose() || with_reduced_queries())
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
{
return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
} else {
p!(print_def_path(self.def_id, self.args));
}
}
}
}
ty::TraitPredicate<'tcx> { ty::TraitPredicate<'tcx> {
p!(print(self.trait_ref.self_ty()), ": "); p!(print(self.trait_ref.self_ty()), ": ");
p!(pretty_print_bound_constness(self.trait_ref)); p!(pretty_print_bound_constness(self.trait_ref));
@ -3205,33 +3232,6 @@ define_print_and_forward_display! {
} }
} }
ty::AliasTy<'tcx> {
let alias_term: ty::AliasTerm<'tcx> = (*self).into();
p!(print(alias_term))
}
ty::AliasTerm<'tcx> {
match self.kind(cx.tcx()) {
ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
ty::AliasTermKind::ProjectionTy
| ty::AliasTermKind::WeakTy
| ty::AliasTermKind::OpaqueTy
| ty::AliasTermKind::UnevaluatedConst
| ty::AliasTermKind::ProjectionConst => {
// If we're printing verbosely, or don't want to invoke queries
// (`is_impl_trait_in_trait`), then fall back to printing the def path.
// This is likely what you want if you're debugging the compiler anyways.
if !(cx.should_print_verbose() || with_reduced_queries())
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
{
return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
} else {
p!(print_def_path(self.def_id, self.args));
}
}
}
}
ty::Predicate<'tcx> { ty::Predicate<'tcx> {
p!(print(self.kind())) p!(print(self.kind()))
} }

View file

@ -7,7 +7,7 @@ use crate::mir::interpret;
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_ast_ir::try_visit; use rustc_ast_ir::try_visit;
use rustc_ast_ir::visit::VisitorResult; use rustc_ast_ir::visit::VisitorResult;
use rustc_hir::def::Namespace; use rustc_hir::def::Namespace;
@ -164,23 +164,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
} }
} }
impl<'tcx> fmt::Debug for AliasTy<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
f.debug_struct("AliasTy")
.field("args", &this.map(|data| data.args))
.field("def_id", &this.data.def_id)
.finish()
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
@ -230,23 +213,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
} }
} }
impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
f.debug_struct("UnevaluatedConst")
.field("def", &this.data.def)
.field("args", &this.wrap(this.data.args))
.finish()
}
}
impl<'tcx> fmt::Debug for ty::Const<'tcx> { impl<'tcx> fmt::Debug for ty::Const<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)

View file

@ -28,20 +28,17 @@ use std::iter;
use std::ops::{ControlFlow, Deref, Range}; use std::ops::{ControlFlow, Deref, Range};
use ty::util::IntTypeExt; use ty::util::IntTypeExt;
use rustc_type_ir::BoundVar;
use rustc_type_ir::CollectAndApply;
use rustc_type_ir::DynKind;
use rustc_type_ir::TyKind as IrTyKind;
use rustc_type_ir::TyKind::*; use rustc_type_ir::TyKind::*;
use rustc_type_ir::TypeAndMut as IrTypeAndMut; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
use super::fold::FnMutDelegate; use super::fold::FnMutDelegate;
use super::GenericParamDefKind; use super::GenericParamDefKind;
// Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
#[rustc_diagnostic_item = "TyKind"] #[rustc_diagnostic_item = "TyKind"]
pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>; pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
pub type TypeAndMut<'tcx> = IrTypeAndMut<TyCtxt<'tcx>>; pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
pub trait Article { pub trait Article {
fn article(&self) -> &'static str; fn article(&self) -> &'static str;
@ -1105,371 +1102,6 @@ where
} }
} }
/// Represents the unprojected term of a projection goal.
///
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
/// * For an inherent projection, this would be `Ty::N<...>`.
/// * For an opaque type, there is no explicit syntax.
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct AliasTerm<'tcx> {
/// The parameters of the associated or opaque item.
///
/// For a projection, these are the generic parameters for the trait and the
/// GAT parameters, if there are any.
///
/// For an inherent projection, they consist of the self type and the GAT parameters,
/// if there are any.
///
/// For RPIT the generic parameters are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub args: GenericArgsRef<'tcx>,
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
/// this is an opaque.
///
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
/// underlying type if the type is an opaque.
///
/// Note that if this is an associated type, this is not the `DefId` of the
/// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
/// aka. `tcx.parent(def_id)`.
pub def_id: DefId,
/// This field exists to prevent the creation of `AliasTerm` without using
/// [AliasTerm::new].
_use_alias_term_new_instead: (),
}
// FIXME: Remove these when we uplift `AliasTerm`
use crate::ty::{DebugWithInfcx, InferCtxtLike, WithInfcx};
impl<'tcx> std::fmt::Debug for AliasTerm<'tcx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTerm<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
f.debug_struct("AliasTerm")
.field("args", &this.map(|data| data.args))
.field("def_id", &this.data.def_id)
.finish()
}
}
impl<'tcx> rustc_type_ir::inherent::AliasTerm<TyCtxt<'tcx>> for AliasTerm<'tcx> {
fn new(
interner: TyCtxt<'tcx>,
trait_def_id: DefId,
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
) -> Self {
AliasTerm::new(interner, trait_def_id, args)
}
fn def_id(self) -> DefId {
self.def_id
}
fn args(self) -> ty::GenericArgsRef<'tcx> {
self.args
}
fn trait_def_id(self, interner: TyCtxt<'tcx>) -> DefId {
self.trait_def_id(interner)
}
fn self_ty(self) -> Ty<'tcx> {
self.self_ty()
}
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
self.with_self_ty(tcx, self_ty)
}
}
impl<'tcx> AliasTerm<'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
def_id: DefId,
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
) -> AliasTerm<'tcx> {
let args = tcx.check_and_mk_args(def_id, args);
AliasTerm { def_id, args, _use_alias_term_new_instead: () }
}
pub fn expect_ty(self, tcx: TyCtxt<'tcx>) -> AliasTy<'tcx> {
match self.kind(tcx) {
ty::AliasTermKind::ProjectionTy
| ty::AliasTermKind::InherentTy
| ty::AliasTermKind::OpaqueTy
| ty::AliasTermKind::WeakTy => {}
ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
bug!("Cannot turn `UnevaluatedConst` into `AliasTy`")
}
}
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
}
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTermKind {
match tcx.def_kind(self.def_id) {
DefKind::AssocTy => {
if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) {
ty::AliasTermKind::InherentTy
} else {
ty::AliasTermKind::ProjectionTy
}
}
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
DefKind::TyAlias => ty::AliasTermKind::WeakTy,
DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
}
}
/// The following methods work only with (trait) associated item projections.
impl<'tcx> AliasTerm<'tcx> {
pub fn self_ty(self) -> Ty<'tcx> {
self.args.type_at(0)
}
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
AliasTerm::new(
tcx,
self.def_id,
[self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
)
}
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
match tcx.def_kind(self.def_id) {
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
kind => bug!("expected a projection AliasTy; found {kind:?}"),
}
}
/// Extracts the underlying trait reference from this projection.
/// For example, if this is a projection of `<T as Iterator>::Item`,
/// then this function would return a `T: Iterator` trait reference.
///
/// NOTE: This will drop the args for generic associated types
/// consider calling [Self::trait_ref_and_own_args] to get those
/// as well.
pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
let def_id = self.trait_def_id(tcx);
ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id)))
}
/// Extracts the underlying trait reference and own args from this projection.
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
/// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args
pub fn trait_ref_and_own_args(
self,
tcx: TyCtxt<'tcx>,
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
let trait_def_id = self.trait_def_id(tcx);
let trait_generics = tcx.generics_of(trait_def_id);
(
ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)),
&self.args[trait_generics.count()..],
)
}
pub fn to_term(self, tcx: TyCtxt<'tcx>) -> ty::Term<'tcx> {
match self.kind(tcx) {
ty::AliasTermKind::ProjectionTy => Ty::new_alias(
tcx,
ty::Projection,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
ty::AliasTermKind::InherentTy => Ty::new_alias(
tcx,
ty::Inherent,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
ty::AliasTermKind::OpaqueTy => Ty::new_alias(
tcx,
ty::Opaque,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
ty::AliasTermKind::WeakTy => Ty::new_alias(
tcx,
ty::Weak,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
ty::Const::new_unevaluated(
tcx,
ty::UnevaluatedConst::new(self.def_id, self.args),
tcx.type_of(self.def_id).instantiate(tcx, self.args),
)
.into()
}
}
}
}
impl<'tcx> From<AliasTy<'tcx>> for AliasTerm<'tcx> {
fn from(ty: AliasTy<'tcx>) -> Self {
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
}
}
impl<'tcx> From<ty::UnevaluatedConst<'tcx>> for AliasTerm<'tcx> {
fn from(ct: ty::UnevaluatedConst<'tcx>) -> Self {
AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
}
}
/// Represents the projection of an associated, opaque, or lazy-type-alias type.
///
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
/// * For an inherent projection, this would be `Ty::N<...>`.
/// * For an opaque type, there is no explicit syntax.
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct AliasTy<'tcx> {
/// The parameters of the associated or opaque type.
///
/// For a projection, these are the generic parameters for the trait and the
/// GAT parameters, if there are any.
///
/// For an inherent projection, they consist of the self type and the GAT parameters,
/// if there are any.
///
/// For RPIT the generic parameters are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub args: GenericArgsRef<'tcx>,
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
/// this is an opaque.
///
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
/// underlying type if the type is an opaque.
///
/// Note that if this is an associated type, this is not the `DefId` of the
/// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
/// aka. `tcx.parent(def_id)`.
pub def_id: DefId,
/// This field exists to prevent the creation of `AliasT` without using
/// [AliasTy::new].
_use_alias_ty_new_instead: (),
}
impl<'tcx> AliasTy<'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
def_id: DefId,
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
) -> ty::AliasTy<'tcx> {
let args = tcx.check_and_mk_args(def_id, args);
ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () }
}
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTyKind {
match tcx.def_kind(self.def_id) {
DefKind::AssocTy
if let DefKind::Impl { of_trait: false } =
tcx.def_kind(tcx.parent(self.def_id)) =>
{
ty::Inherent
}
DefKind::AssocTy => ty::Projection,
DefKind::OpaqueTy => ty::Opaque,
DefKind::TyAlias => ty::Weak,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
}
/// Whether this alias type is an opaque.
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
matches!(self.kind(tcx), ty::Opaque)
}
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
Ty::new_alias(tcx, self.kind(tcx), self)
}
}
/// The following methods work only with (trait) associated type projections.
impl<'tcx> AliasTy<'tcx> {
pub fn self_ty(self) -> Ty<'tcx> {
self.args.type_at(0)
}
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1)))
}
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
match tcx.def_kind(self.def_id) {
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
kind => bug!("expected a projection AliasTy; found {kind:?}"),
}
}
/// Extracts the underlying trait reference and own args from this projection.
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
/// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args
pub fn trait_ref_and_own_args(
self,
tcx: TyCtxt<'tcx>,
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
let trait_def_id = self.trait_def_id(tcx);
let trait_generics = tcx.generics_of(trait_def_id);
(
ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)),
&self.args[trait_generics.count()..],
)
}
/// Extracts the underlying trait reference from this projection.
/// For example, if this is a projection of `<T as Iterator>::Item`,
/// then this function would return a `T: Iterator` trait reference.
///
/// WARNING: This will drop the args for generic associated types
/// consider calling [Self::trait_ref_and_own_args] to get those
/// as well.
pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
let def_id = self.trait_def_id(tcx);
ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id)))
}
}
/// The following methods work only with inherent associated type projections.
impl<'tcx> AliasTy<'tcx> {
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
///
/// Does the following transformation:
///
/// ```text
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
///
/// I_i impl args
/// P_j GAT args
/// ```
pub fn rebase_inherent_args_onto_impl(
self,
impl_args: ty::GenericArgsRef<'tcx>,
tcx: TyCtxt<'tcx>,
) -> ty::GenericArgsRef<'tcx> {
debug_assert_eq!(self.kind(tcx), ty::Inherent);
tcx.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
}
}
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
pub struct GenSig<'tcx> { pub struct GenSig<'tcx> {
pub resume_ty: Ty<'tcx>, pub resume_ty: Ty<'tcx>,
@ -2020,6 +1652,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
} }
fn new_alias(
interner: TyCtxt<'tcx>,
kind: ty::AliasTyKind,
alias_ty: ty::AliasTy<'tcx>,
) -> Self {
Ty::new_alias(interner, kind, alias_ty)
}
} }
/// Type utilities /// Type utilities

View file

@ -1130,7 +1130,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> {
} }
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) { if !ct.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
return ct; return ct;
} }
ct.super_fold_with(self) ct.super_fold_with(self)

View file

@ -61,17 +61,7 @@ fn coverage_ids_info<'tcx>(
.max() .max()
.unwrap_or(CounterId::ZERO); .unwrap_or(CounterId::ZERO);
let mcdc_bitmap_bytes = mir_body CoverageIdsInfo { max_counter_id }
.coverage_branch_info
.as_deref()
.map(|info| {
info.mcdc_decision_spans
.iter()
.fold(0, |acc, decision| acc + (1_u32 << decision.conditions_num).div_ceil(8))
})
.unwrap_or_default();
CoverageIdsInfo { max_counter_id, mcdc_bitmap_bytes }
} }
fn all_coverage_in_mir_body<'a, 'tcx>( fn all_coverage_in_mir_body<'a, 'tcx>(

View file

@ -686,20 +686,35 @@ impl<'a> Parser<'a> {
(None, self.parse_path(PathStyle::Expr)?) (None, self.parse_path(PathStyle::Expr)?)
}; };
let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None }; let rename = |this: &mut Self| {
Ok(if this.eat_keyword(kw::As) { Some(this.parse_ident()?) } else { None })
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
Some(self.parse_block()?)
} else {
self.expect(&token::Semi)?;
None
}; };
let body = |this: &mut Self| {
Ok(if this.check(&token::OpenDelim(Delimiter::Brace)) {
Some(this.parse_block()?)
} else {
this.expect(&token::Semi)?;
None
})
};
let (ident, item_kind) = if self.eat(&token::PathSep) {
let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| {
Ok((p.parse_path_segment_ident()?, rename(p)?))
})?;
let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
(Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
} else {
let rename = rename(self)?;
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body: body(self)? };
(ident, ItemKind::Delegation(Box::new(deleg)))
};
let span = span.to(self.prev_token.span); let span = span.to(self.prev_token.span);
self.psess.gated_spans.gate(sym::fn_delegation, span); self.psess.gated_spans.gate(sym::fn_delegation, span);
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); Ok((ident, item_kind))
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body };
Ok((ident, ItemKind::Delegation(Box::new(deleg))))
} }
fn parse_item_list<T>( fn parse_item_list<T>(

View file

@ -95,12 +95,15 @@ impl<'a> Parser<'a> {
debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
} }
if !self.recover_colon_before_qpath_proj() { let is_import_coupler = self.is_import_coupler();
if !is_import_coupler && !self.recover_colon_before_qpath_proj() {
self.expect(&token::PathSep)?; self.expect(&token::PathSep)?;
} }
let qself = P(QSelf { ty, path_span, position: path.segments.len() }); let qself = P(QSelf { ty, path_span, position: path.segments.len() });
self.parse_path_segments(&mut path.segments, style, None)?; if !is_import_coupler {
self.parse_path_segments(&mut path.segments, style, None)?;
}
Ok(( Ok((
qself, qself,

View file

@ -522,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Impl, Impl,
MacCall, MacCall,
MacroDef, MacroDef,
Delegation Delegation,
DelegationMac
] ]
); );
ast_visit::walk_item(self, i) ast_visit::walk_item(self, i)
@ -650,7 +651,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
record_variants!( record_variants!(
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind), (self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
[Const, Fn, Type, MacCall, Delegation] [Const, Fn, Type, MacCall, Delegation, DelegationMac]
); );
ast_visit::walk_assoc_item(self, i, ctxt); ast_visit::walk_assoc_item(self, i, ctxt);
} }

View file

@ -285,7 +285,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias, ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias,
ast::ItemKind::Impl(_) => Target::Impl, ast::ItemKind::Impl(_) => Target::Impl,
ast::ItemKind::MacroDef(_) => Target::MacroDef, ast::ItemKind::MacroDef(_) => Target::MacroDef,
ast::ItemKind::MacCall(_) => unreachable!("macros should have been expanded"), ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => {
unreachable!("macros should have been expanded")
}
}; };
self.check_for_lang( self.check_for_lang(
@ -340,7 +342,9 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
} }
ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)), ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)), ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"), ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(_) => {
unreachable!("macros should have been expanded")
}
}; };
self.check_for_lang( self.check_for_lang(

View file

@ -825,7 +825,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
} }
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(), ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
unreachable!()
}
} }
} }
@ -1381,7 +1383,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
| AssocItemKind::Delegation(..) | AssocItemKind::Delegation(..)
| AssocItemKind::Fn(..) => ValueNS, | AssocItemKind::Fn(..) => ValueNS,
AssocItemKind::Type(..) => TypeNS, AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) => bug!(), // handled above AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
}; };
let parent = self.parent_scope.module; let parent = self.parent_scope.module;

View file

@ -139,6 +139,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
ItemKind::Use(..) => return visit::walk_item(self, i), ItemKind::Use(..) => return visit::walk_item(self, i),
ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
ItemKind::DelegationMac(..) => unreachable!(),
}; };
let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span); let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
@ -278,6 +279,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
AssocItemKind::Const(..) => DefKind::AssocConst, AssocItemKind::Const(..) => DefKind::AssocConst,
AssocItemKind::Type(..) => DefKind::AssocTy, AssocItemKind::Type(..) => DefKind::AssocTy,
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
AssocItemKind::DelegationMac(..) => unreachable!(),
}; };
let def = self.create_def(i.id, i.ident.name, def_kind, i.span); let def = self.create_def(i.id, i.ident.name, def_kind, i.span);

View file

@ -236,7 +236,7 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't
ast::ItemKind::Impl(..) => return, ast::ItemKind::Impl(..) => return,
// Should be unreachable at this stage // Should be unreachable at this stage
ast::ItemKind::MacCall(..) => panic!( ast::ItemKind::MacCall(..) | ast::ItemKind::DelegationMac(..) => panic!(
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage" "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
), ),

View file

@ -2561,7 +2561,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ItemKind::ExternCrate(..) => {} ItemKind::ExternCrate(..) => {}
ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"), ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
panic!("unexpanded macro in resolve!")
}
} }
} }
@ -2849,7 +2851,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
}), }),
AssocItemKind::MacCall(_) => { AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
panic!("unexpanded macro in resolve!") panic!("unexpanded macro in resolve!")
} }
}; };
@ -3116,7 +3118,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}, },
); );
} }
AssocItemKind::MacCall(_) => { AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
panic!("unexpanded macro in resolve!") panic!("unexpanded macro in resolve!")
} }
} }
@ -3218,7 +3220,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
AssocItemKind::Fn(..) => (E0324, "method"), AssocItemKind::Fn(..) => (E0324, "method"),
AssocItemKind::Type(..) => (E0325, "type"), AssocItemKind::Type(..) => (E0325, "type"),
AssocItemKind::Delegation(..) => (E0324, "method"), AssocItemKind::Delegation(..) => (E0324, "method"),
AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
span_bug!(span, "unexpanded macro")
}
}; };
let trait_path = path_names_to_string(path); let trait_path = path_names_to_string(path);
self.report_error( self.report_error(
@ -4790,7 +4794,8 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
| ItemKind::ExternCrate(..) | ItemKind::ExternCrate(..)
| ItemKind::MacroDef(..) | ItemKind::MacroDef(..)
| ItemKind::GlobalAsm(..) | ItemKind::GlobalAsm(..)
| ItemKind::MacCall(..) => {} | ItemKind::MacCall(..)
| ItemKind::DelegationMac(..) => {}
ItemKind::Delegation(..) => { ItemKind::Delegation(..) => {
// Delegated functions have lifetimes, their count is not necessarily zero. // Delegated functions have lifetimes, their count is not necessarily zero.
// But skipping the delegation items here doesn't mean that the count will be considered zero, // But skipping the delegation items here doesn't mean that the count will be considered zero,

View file

@ -2045,7 +2045,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
AssocSuggestion::MethodWithSelf { called } AssocSuggestion::MethodWithSelf { called }
} }
ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called }, ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::MacCall(_) => continue, ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => {
continue;
}
}); });
} }
} }

View file

@ -29,6 +29,7 @@ use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES}; use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::BuiltinLintDiag;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::edit_distance::edit_distance;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId};
use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::hygiene::{AstPass, MacroKind};
@ -568,15 +569,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
&& path.segments.len() >= 2 && let [namespace, attribute, ..] = &*path.segments
&& path.segments[0].ident.name == sym::diagnostic && namespace.ident.name == sym::diagnostic
&& path.segments[1].ident.name != sym::on_unimplemented && attribute.ident.name != sym::on_unimplemented
{ {
self.tcx.sess.psess.buffer_lint( let distance =
edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);
let help = if distance.is_some() {
BuiltinLintDiag::MaybeTypo { span: attribute.span(), name: sym::on_unimplemented }
} else {
BuiltinLintDiag::Normal
};
self.tcx.sess.psess.buffer_lint_with_diagnostic(
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
path.segments[1].span(), attribute.span(),
node_id, node_id,
"unknown diagnostic attribute", "unknown diagnostic attribute",
help,
); );
} }

View file

@ -779,16 +779,21 @@ impl RiscvInterruptKind {
/// Metadata describing how the arguments to a native function /// Metadata describing how the arguments to a native function
/// should be passed in order to respect the native ABI. /// should be passed in order to respect the native ABI.
/// ///
/// The signature represented by this type may not match the MIR function signature.
/// Certain attributes, like `#[track_caller]` can introduce additional arguments, which are present in [`FnAbi`], but not in `FnSig`.
/// While this difference is rarely relevant, it should still be kept in mind.
///
/// I will do my best to describe this structure, but these /// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM /// comments are reverse-engineered and may be inaccurate. -NDM
#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)] #[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
pub struct FnAbi<'a, Ty> { pub struct FnAbi<'a, Ty> {
/// The LLVM types of each argument. /// The type, layout, and information about how each argument is passed.
pub args: Box<[ArgAbi<'a, Ty>]>, pub args: Box<[ArgAbi<'a, Ty>]>,
/// LLVM return type. /// The layout, type, and the way a value is returned from this function.
pub ret: ArgAbi<'a, Ty>, pub ret: ArgAbi<'a, Ty>,
/// Marks this function as variadic (accepting a variable number of arguments).
pub c_variadic: bool, pub c_variadic: bool,
/// The count of non-variadic arguments. /// The count of non-variadic arguments.
@ -796,9 +801,9 @@ pub struct FnAbi<'a, Ty> {
/// Should only be different from args.len() when c_variadic is true. /// Should only be different from args.len() when c_variadic is true.
/// This can be used to know whether an argument is variadic or not. /// This can be used to know whether an argument is variadic or not.
pub fixed_count: u32, pub fixed_count: u32,
/// The calling convention of this function.
pub conv: Conv, pub conv: Conv,
/// Indicates if an unwind may happen across a call to this function.
pub can_unwind: bool, pub can_unwind: bool,
} }

View file

@ -1,7 +1,7 @@
//! Code shared by trait and projection goals for candidate assembly. //! Code shared by trait and projection goals for candidate assembly.
use crate::solve::GoalSource; use crate::solve::GoalSource;
use crate::solve::{inspect, EvalCtxt, SolverMode}; use crate::solve::{EvalCtxt, SolverMode};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_middle::bug; use rustc_middle::bug;
@ -16,7 +16,6 @@ use rustc_middle::ty::{fast_reject, TypeFoldable};
use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, DUMMY_SP}; use rustc_span::{ErrorGuaranteed, DUMMY_SP};
use std::fmt::Debug; use std::fmt::Debug;
use std::mem;
pub(super) mod structural_traits; pub(super) mod structural_traits;
@ -792,17 +791,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
goal: Goal<'tcx, G>, goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>, candidates: &mut Vec<Candidate<'tcx>>,
) { ) {
// HACK: We temporarily remove the `ProofTreeBuilder` to
// avoid adding `Trait` candidates to the candidates used
// to prove the current goal.
let inspect = mem::replace(&mut self.inspect, inspect::ProofTreeBuilder::new_noop());
let tcx = self.tcx(); let tcx = self.tcx();
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
goal.with(tcx, goal.predicate.trait_ref(tcx)); goal.with(tcx, goal.predicate.trait_ref(tcx));
let mut trait_candidates_from_env = Vec::new();
self.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env); let mut trait_candidates_from_env = vec![];
self.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env); self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
ecx.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
ecx.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
});
if !trait_candidates_from_env.is_empty() { if !trait_candidates_from_env.is_empty() {
let trait_env_result = self.merge_candidates(trait_candidates_from_env); let trait_env_result = self.merge_candidates(trait_candidates_from_env);
match trait_env_result.unwrap().value.certainty { match trait_env_result.unwrap().value.certainty {
@ -831,7 +829,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
} }
} }
} }
self.inspect = inspect;
} }
/// If there are multiple ways to prove a trait or projection goal, we have /// If there are multiple ways to prove a trait or projection goal, we have

View file

@ -176,7 +176,8 @@ fn to_selection<'tcx>(
| ProbeKind::UnsizeAssembly | ProbeKind::UnsizeAssembly
| ProbeKind::UpcastProjectionCompatibility | ProbeKind::UpcastProjectionCompatibility
| ProbeKind::OpaqueTypeStorageLookup { result: _ } | ProbeKind::OpaqueTypeStorageLookup { result: _ }
| ProbeKind::Root { result: _ } => { | ProbeKind::Root { result: _ }
| ProbeKind::ShadowedEnvProbing => {
span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind()) span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind())
} }
}) })

View file

@ -18,8 +18,8 @@ use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{inspect, QueryResult}; use rustc_middle::traits::solve::{inspect, QueryResult};
use rustc_middle::traits::solve::{Certainty, Goal}; use rustc_middle::traits::solve::{Certainty, Goal};
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::ty;
use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::TypeFoldable;
use rustc_middle::{bug, ty};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use crate::solve::eval_ctxt::canonical; use crate::solve::eval_ctxt::canonical;
@ -290,12 +290,25 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
match *step { match *step {
inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
inspect::ProbeStep::NestedProbe(ref probe) => { inspect::ProbeStep::NestedProbe(ref probe) => {
// Nested probes have to prove goals added in their parent match probe.kind {
// but do not leak them, so we truncate the added goals // These never assemble candidates for the goal we're trying to solve.
// afterwards. inspect::ProbeKind::UpcastProjectionCompatibility
let num_goals = nested_goals.len(); | inspect::ProbeKind::ShadowedEnvProbing => continue,
self.candidates_recur(candidates, nested_goals, probe);
nested_goals.truncate(num_goals); inspect::ProbeKind::NormalizedSelfTyAssembly
| inspect::ProbeKind::UnsizeAssembly
| inspect::ProbeKind::Root { .. }
| inspect::ProbeKind::TryNormalizeNonRigid { .. }
| inspect::ProbeKind::TraitCandidate { .. }
| inspect::ProbeKind::OpaqueTypeStorageLookup { .. } => {
// Nested probes have to prove goals added in their parent
// but do not leak them, so we truncate the added goals
// afterwards.
let num_goals = nested_goals.len();
self.candidates_recur(candidates, nested_goals, probe);
nested_goals.truncate(num_goals);
}
}
} }
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
assert_eq!(shallow_certainty.replace(c), None); assert_eq!(shallow_certainty.replace(c), None);
@ -308,9 +321,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
} }
match probe.kind { match probe.kind {
inspect::ProbeKind::NormalizedSelfTyAssembly inspect::ProbeKind::UpcastProjectionCompatibility
| inspect::ProbeKind::UnsizeAssembly | inspect::ProbeKind::ShadowedEnvProbing => bug!(),
| inspect::ProbeKind::UpcastProjectionCompatibility => (),
inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
// We add a candidate even for the root evaluation if there // We add a candidate even for the root evaluation if there
// is only one way to prove a given goal, e.g. for `WellFormed`. // is only one way to prove a given goal, e.g. for `WellFormed`.

View file

@ -2,6 +2,7 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use std::fmt; use std::fmt;
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
@ -86,6 +87,46 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
} }
} }
/// An unevaluated (potentially generic) constant used in the type-system.
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct UnevaluatedConst<I: Interner> {
pub def: I::DefId,
pub args: I::GenericArgs,
}
impl<I: Interner> UnevaluatedConst<I> {
#[inline]
pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst<I> {
UnevaluatedConst { def, args }
}
}
impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
f.debug_struct("UnevaluatedConst")
.field("def", &this.data.def)
.field("args", &this.wrap(this.data.args))
.finish()
}
}
rustc_index::newtype_index! { rustc_index::newtype_index! {
/// A **`const`** **v**ariable **ID**. /// A **`const`** **v**ariable **ID**.
#[encodable] #[encodable]

View file

@ -5,7 +5,8 @@ use std::ops::Deref;
use crate::fold::TypeSuperFoldable; use crate::fold::TypeSuperFoldable;
use crate::visit::{Flags, TypeSuperVisitable}; use crate::visit::{Flags, TypeSuperVisitable};
use crate::{ use crate::{
BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, TyKind, UniverseIndex, AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind,
TyKind, UnevaluatedConst, UniverseIndex,
}; };
pub trait Ty<I: Interner<Ty = Self>>: pub trait Ty<I: Interner<Ty = Self>>:
@ -14,12 +15,15 @@ pub trait Ty<I: Interner<Ty = Self>>:
+ Hash + Hash
+ Eq + Eq
+ Into<I::GenericArg> + Into<I::GenericArg>
+ Into<I::Term>
+ IntoKind<Kind = TyKind<I>> + IntoKind<Kind = TyKind<I>>
+ TypeSuperVisitable<I> + TypeSuperVisitable<I>
+ TypeSuperFoldable<I> + TypeSuperFoldable<I>
+ Flags + Flags
{ {
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
} }
pub trait Region<I: Interner<Region = Self>>: pub trait Region<I: Interner<Region = Self>>:
@ -36,6 +40,7 @@ pub trait Const<I: Interner<Const = Self>>:
+ Hash + Hash
+ Eq + Eq
+ Into<I::GenericArg> + Into<I::GenericArg>
+ Into<I::Term>
+ IntoKind<Kind = ConstKind<I>> + IntoKind<Kind = ConstKind<I>>
+ TypeSuperVisitable<I> + TypeSuperVisitable<I>
+ TypeSuperFoldable<I> + TypeSuperFoldable<I>
@ -43,6 +48,8 @@ pub trait Const<I: Interner<Const = Self>>:
{ {
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self;
fn ty(self) -> I::Ty; fn ty(self) -> I::Ty;
} }
@ -89,21 +96,3 @@ pub trait BoundVars<I: Interner> {
fn has_no_bound_vars(&self) -> bool; fn has_no_bound_vars(&self) -> bool;
} }
pub trait AliasTerm<I: Interner>: Copy + DebugWithInfcx<I> + Hash + Eq + Sized {
fn new(
interner: I,
trait_def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> Self;
fn def_id(self) -> I::DefId;
fn args(self) -> I::GenericArgs;
fn trait_def_id(self, interner: I) -> I::DefId;
fn self_ty(self) -> I::Ty;
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self;
}

View file

@ -6,13 +6,16 @@ use crate::inherent::*;
use crate::ir_print::IrPrint; use crate::ir_print::IrPrint;
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{ use crate::{
CanonicalVarInfo, CoercePredicate, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate,
SubtypePredicate, TraitPredicate, TraitRef,
}; };
pub trait Interner: pub trait Interner:
Sized Sized
+ Copy + Copy
+ IrPrint<AliasTy<Self>>
+ IrPrint<AliasTerm<Self>>
+ IrPrint<TraitRef<Self>> + IrPrint<TraitRef<Self>>
+ IrPrint<TraitPredicate<Self>> + IrPrint<TraitPredicate<Self>>
+ IrPrint<ExistentialTraitRef<Self>> + IrPrint<ExistentialTraitRef<Self>>
@ -27,6 +30,7 @@ pub trait Interner:
type AdtDef: Copy + Debug + Hash + Eq; type AdtDef: Copy + Debug + Hash + Eq;
type GenericArgs: GenericArgs<Self>; type GenericArgs: GenericArgs<Self>;
type GenericArgsSlice: Copy + Debug + Hash + Eq;
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq; type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq;
type Term: Copy + Debug + Hash + Eq; type Term: Copy + Debug + Hash + Eq;
@ -39,7 +43,6 @@ pub trait Interner:
// Kinds of tys // Kinds of tys
type Ty: Ty<Self>; type Ty: Ty<Self>;
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>; type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Eq + Sized;
type ParamTy: Copy + Debug + Hash + Eq; type ParamTy: Copy + Debug + Hash + Eq;
type BoundTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq;
type PlaceholderTy: PlaceholderLike; type PlaceholderTy: PlaceholderLike;
@ -74,7 +77,6 @@ pub trait Interner:
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
type ProjectionPredicate: Copy + Debug + Hash + Eq; type ProjectionPredicate: Copy + Debug + Hash + Eq;
type AliasTerm: AliasTerm<Self>;
type NormalizesTo: Copy + Debug + Hash + Eq; type NormalizesTo: Copy + Debug + Hash + Eq;
type SubtypePredicate: Copy + Debug + Hash + Eq; type SubtypePredicate: Copy + Debug + Hash + Eq;
type CoercePredicate: Copy + Debug + Hash + Eq; type CoercePredicate: Copy + Debug + Hash + Eq;
@ -86,8 +88,23 @@ pub trait Interner:
type GenericsOf: GenericsOf<Self>; type GenericsOf: GenericsOf<Self>;
fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
// FIXME: Remove after uplifting `EarlyBinder`
fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty;
fn alias_ty_kind(self, alias: AliasTy<Self>) -> AliasTyKind;
fn alias_term_kind(self, alias: AliasTerm<Self>) -> AliasTermKind;
fn trait_ref_and_own_args_for_alias(
self,
def_id: Self::DefId,
args: Self::GenericArgs,
) -> (TraitRef<Self>, Self::GenericArgsSlice);
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs;
fn check_and_mk_args( fn check_and_mk_args(
self, self,
def_id: Self::DefId, def_id: Self::DefId,

View file

@ -1,8 +1,8 @@
use std::fmt; use std::fmt;
use crate::{ use crate::{
CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, NormalizesTo, AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner,
ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
}; };
pub trait IrPrint<T> { pub trait IrPrint<T> {
@ -43,6 +43,8 @@ define_display_via_print!(
NormalizesTo, NormalizesTo,
SubtypePredicate, SubtypePredicate,
CoercePredicate, CoercePredicate,
AliasTy,
AliasTerm,
); );
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);

View file

@ -6,7 +6,9 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
use crate::inherent::*; use crate::inherent::*;
use crate::visit::TypeVisitableExt as _; use crate::visit::TypeVisitableExt as _;
use crate::{DebugWithInfcx, Interner}; use crate::{
AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx,
};
/// A complete reference to a trait. These take numerous guises in syntax, /// A complete reference to a trait. These take numerous guises in syntax,
/// but perhaps the most recognizable form is in a where-clause: /// but perhaps the most recognizable form is in a where-clause:
@ -272,20 +274,20 @@ impl<I: Interner> ExistentialProjection<I> {
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`, /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
/// then this function would return an `exists T. T: Iterator` existential trait /// then this function would return an `exists T. T: Iterator` existential trait
/// reference. /// reference.
pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef<I> { pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef<I> {
let def_id = tcx.parent(self.def_id); let def_id = interner.parent(self.def_id);
let args_count = tcx.generics_of(def_id).count() - 1; let args_count = interner.generics_of(def_id).count() - 1;
let args = tcx.mk_args(&self.args[..args_count]); let args = interner.mk_args(&self.args[..args_count]);
ExistentialTraitRef { def_id, args } ExistentialTraitRef { def_id, args }
} }
pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate<I> { pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
// otherwise the escaping regions would be captured by the binders // otherwise the escaping regions would be captured by the binders
debug_assert!(!self_ty.has_escaping_bound_vars()); debug_assert!(!self_ty.has_escaping_bound_vars());
ProjectionPredicate { ProjectionPredicate {
projection_term: I::AliasTerm::new( projection_term: AliasTerm::new(
tcx, interner,
self.def_id, self.def_id,
[self_ty.into()].into_iter().chain(self.args), [self_ty.into()].into_iter().chain(self.args),
), ),
@ -293,13 +295,13 @@ impl<I: Interner> ExistentialProjection<I> {
} }
} }
pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate<I>) -> Self { pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate<I>) -> Self {
// Assert there is a Self. // Assert there is a Self.
projection_predicate.projection_term.args().type_at(0); projection_predicate.projection_term.args.type_at(0);
Self { Self {
def_id: projection_predicate.projection_term.def_id(), def_id: projection_predicate.projection_term.def_id,
args: tcx.mk_args(&projection_predicate.projection_term.args()[1..]), args: interner.mk_args(&projection_predicate.projection_term.args[1..]),
term: projection_predicate.term, term: projection_predicate.term,
} }
} }
@ -339,6 +341,190 @@ impl AliasTermKind {
} }
} }
/// Represents the unprojected term of a projection goal.
///
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
/// * For an inherent projection, this would be `Ty::N<...>`.
/// * For an opaque type, there is no explicit syntax.
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct AliasTerm<I: Interner> {
/// The parameters of the associated or opaque item.
///
/// For a projection, these are the generic parameters for the trait and the
/// GAT parameters, if there are any.
///
/// For an inherent projection, they consist of the self type and the GAT parameters,
/// if there are any.
///
/// For RPIT the generic parameters are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub args: I::GenericArgs,
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
/// this is an opaque.
///
/// During codegen, `interner.type_of(def_id)` can be used to get the type of the
/// underlying type if the type is an opaque.
///
/// Note that if this is an associated type, this is not the `DefId` of the
/// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
/// aka. `interner.parent(def_id)`.
pub def_id: I::DefId,
/// This field exists to prevent the creation of `AliasTerm` without using
/// [AliasTerm::new].
_use_alias_term_new_instead: (),
}
impl<I: Interner> std::fmt::Debug for AliasTerm<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<I: Interner> DebugWithInfcx<I> for AliasTerm<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
f.debug_struct("AliasTerm")
.field("args", &this.map(|data| data.args))
.field("def_id", &this.data.def_id)
.finish()
}
}
impl<I: Interner> AliasTerm<I> {
pub fn new(
interner: I,
def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> AliasTerm<I> {
let args = interner.check_and_mk_args(def_id, args);
AliasTerm { def_id, args, _use_alias_term_new_instead: () }
}
pub fn expect_ty(self, interner: I) -> AliasTy<I> {
match self.kind(interner) {
AliasTermKind::ProjectionTy
| AliasTermKind::InherentTy
| AliasTermKind::OpaqueTy
| AliasTermKind::WeakTy => {}
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
}
}
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
}
pub fn kind(self, interner: I) -> AliasTermKind {
interner.alias_term_kind(self)
}
pub fn to_term(self, interner: I) -> I::Term {
match self.kind(interner) {
AliasTermKind::ProjectionTy => Ty::new_alias(
interner,
AliasTyKind::Projection,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
AliasTermKind::InherentTy => Ty::new_alias(
interner,
AliasTyKind::Inherent,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
AliasTermKind::OpaqueTy => Ty::new_alias(
interner,
AliasTyKind::Opaque,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
AliasTermKind::WeakTy => Ty::new_alias(
interner,
AliasTyKind::Weak,
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
)
.into(),
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
I::Const::new_unevaluated(
interner,
UnevaluatedConst::new(self.def_id, self.args),
interner.type_of_instantiated(self.def_id, self.args),
)
.into()
}
}
}
}
/// The following methods work only with (trait) associated type projections.
impl<I: Interner> AliasTerm<I> {
pub fn self_ty(self) -> I::Ty {
self.args.type_at(0)
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
AliasTerm::new(
interner,
self.def_id,
[self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
)
}
pub fn trait_def_id(self, interner: I) -> I::DefId {
assert!(
matches!(
self.kind(interner),
AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst
),
"expected a projection"
);
interner.parent(self.def_id)
}
/// Extracts the underlying trait reference and own args from this projection.
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
/// then this function would return a `T: StreamingIterator` trait reference and
/// `['a]` as the own args.
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
}
/// Extracts the underlying trait reference from this projection.
/// For example, if this is a projection of `<T as Iterator>::Item`,
/// then this function would return a `T: Iterator` trait reference.
///
/// WARNING: This will drop the args for generic associated types
/// consider calling [Self::trait_ref_and_own_args] to get those
/// as well.
pub fn trait_ref(self, interner: I) -> TraitRef<I> {
self.trait_ref_and_own_args(interner).0
}
}
impl<I: Interner> From<AliasTy<I>> for AliasTerm<I> {
fn from(ty: AliasTy<I>) -> Self {
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
}
}
impl<I: Interner> From<UnevaluatedConst<I>> for AliasTerm<I> {
fn from(ct: UnevaluatedConst<I>) -> Self {
AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
}
}
/// This kind of predicate has no *direct* correspondent in the /// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms: /// syntax, but it roughly corresponds to the syntactic forms:
/// ///
@ -362,7 +548,7 @@ impl AliasTermKind {
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct ProjectionPredicate<I: Interner> { pub struct ProjectionPredicate<I: Interner> {
pub projection_term: I::AliasTerm, pub projection_term: AliasTerm<I>,
pub term: I::Term, pub term: I::Term,
} }
@ -371,16 +557,16 @@ impl<I: Interner> ProjectionPredicate<I> {
self.projection_term.self_ty() self.projection_term.self_ty()
} }
pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate<I> { pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
Self { projection_term: self.projection_term.with_self_ty(tcx, self_ty), ..self } Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self }
} }
pub fn trait_def_id(self, tcx: I) -> I::DefId { pub fn trait_def_id(self, interner: I) -> I::DefId {
self.projection_term.trait_def_id(tcx) self.projection_term.trait_def_id(interner)
} }
pub fn def_id(self) -> I::DefId { pub fn def_id(self) -> I::DefId {
self.projection_term.def_id() self.projection_term.def_id
} }
} }
@ -403,7 +589,7 @@ impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct NormalizesTo<I: Interner> { pub struct NormalizesTo<I: Interner> {
pub alias: I::AliasTerm, pub alias: AliasTerm<I>,
pub term: I::Term, pub term: I::Term,
} }
@ -412,16 +598,16 @@ impl<I: Interner> NormalizesTo<I> {
self.alias.self_ty() self.alias.self_ty()
} }
pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo<I> { pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> {
Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } Self { alias: self.alias.with_self_ty(interner, self_ty), ..self }
} }
pub fn trait_def_id(self, tcx: I) -> I::DefId { pub fn trait_def_id(self, interner: I) -> I::DefId {
self.alias.trait_def_id(tcx) self.alias.trait_def_id(interner)
} }
pub fn def_id(self) -> I::DefId { pub fn def_id(self) -> I::DefId {
self.alias.def_id() self.alias.def_id
} }
} }

View file

@ -4,11 +4,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use std::fmt; use std::fmt;
use crate::Interner; use crate::inherent::*;
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx}; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx};
use self::TyKind::*; use self::TyKind::*;
@ -88,7 +88,7 @@ pub enum TyKind<I: Interner> {
/// for `struct List<T>` and the args `[i32]`. /// for `struct List<T>` and the args `[i32]`.
/// ///
/// Note that generic parameters in fields only get lazily instantiated /// Note that generic parameters in fields only get lazily instantiated
/// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`. /// by using something like `adt_def.all_fields().map(|field| field.ty(interner, args))`.
Adt(I::AdtDef, I::GenericArgs), Adt(I::AdtDef, I::GenericArgs),
/// An unsized FFI type that is opaque to Rust. Written as `extern type T`. /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
@ -201,7 +201,7 @@ pub enum TyKind<I: Interner> {
/// A projection, opaque type, weak type alias, or inherent associated type. /// A projection, opaque type, weak type alias, or inherent associated type.
/// All of these types are represented as pairs of def-id and args, and can /// All of these types are represented as pairs of def-id and args, and can
/// be normalized, so they are grouped conceptually. /// be normalized, so they are grouped conceptually.
Alias(AliasTyKind, I::AliasTy), Alias(AliasTyKind, AliasTy<I>),
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}`. /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
Param(I::ParamTy), Param(I::ParamTy),
@ -422,6 +422,154 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
} }
} }
/// Represents the projection of an associated, opaque, or lazy-type-alias type.
///
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
/// * For an inherent projection, this would be `Ty::N<...>`.
/// * For an opaque type, there is no explicit syntax.
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct AliasTy<I: Interner> {
/// The parameters of the associated or opaque type.
///
/// For a projection, these are the generic parameters for the trait and the
/// GAT parameters, if there are any.
///
/// For an inherent projection, they consist of the self type and the GAT parameters,
/// if there are any.
///
/// For RPIT the generic parameters are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub args: I::GenericArgs,
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
/// this is an opaque.
///
/// During codegen, `interner.type_of(def_id)` can be used to get the type of the
/// underlying type if the type is an opaque.
///
/// Note that if this is an associated type, this is not the `DefId` of the
/// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
/// aka. `interner.parent(def_id)`.
pub def_id: I::DefId,
/// This field exists to prevent the creation of `AliasTy` without using
/// [AliasTy::new].
pub(crate) _use_alias_ty_new_instead: (),
}
impl<I: Interner> AliasTy<I> {
pub fn new(
interner: I,
def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> AliasTy<I> {
let args = interner.check_and_mk_args(def_id, args);
AliasTy { def_id, args, _use_alias_ty_new_instead: () }
}
pub fn kind(self, interner: I) -> AliasTyKind {
interner.alias_ty_kind(self)
}
/// Whether this alias type is an opaque.
pub fn is_opaque(self, interner: I) -> bool {
matches!(self.kind(interner), AliasTyKind::Opaque)
}
pub fn to_ty(self, interner: I) -> I::Ty {
Ty::new_alias(interner, self.kind(interner), self)
}
}
/// The following methods work only with (trait) associated type projections.
impl<I: Interner> AliasTy<I> {
pub fn self_ty(self) -> I::Ty {
self.args.type_at(0)
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
AliasTy::new(
interner,
self.def_id,
[self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
)
}
pub fn trait_def_id(self, interner: I) -> I::DefId {
assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection");
interner.parent(self.def_id)
}
/// Extracts the underlying trait reference and own args from this projection.
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
/// then this function would return a `T: StreamingIterator` trait reference and
/// `['a]` as the own args.
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
}
/// Extracts the underlying trait reference from this projection.
/// For example, if this is a projection of `<T as Iterator>::Item`,
/// then this function would return a `T: Iterator` trait reference.
///
/// WARNING: This will drop the args for generic associated types
/// consider calling [Self::trait_ref_and_own_args] to get those
/// as well.
pub fn trait_ref(self, interner: I) -> TraitRef<I> {
self.trait_ref_and_own_args(interner).0
}
}
/// The following methods work only with inherent associated type projections.
impl<I: Interner> AliasTy<I> {
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
///
/// Does the following transformation:
///
/// ```text
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
///
/// I_i impl args
/// P_j GAT args
/// ```
pub fn rebase_inherent_args_onto_impl(
self,
impl_args: I::GenericArgs,
interner: I,
) -> I::GenericArgs {
debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent);
interner.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
}
}
impl<I: Interner> fmt::Debug for AliasTy<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
}
}
impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
f.debug_struct("AliasTy")
.field("args", &this.map(|data| data.args))
.field("def_id", &this.data.def_id)
.finish()
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
pub enum IntTy { pub enum IntTy {

View file

@ -91,17 +91,21 @@ pub struct EscapeDefault(escape::EscapeIterInner<4>);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn escape_default(c: u8) -> EscapeDefault { pub fn escape_default(c: u8) -> EscapeDefault {
let mut data = [Char::Null; 4]; EscapeDefault::new(c)
let range = escape::escape_ascii_into(&mut data, c);
EscapeDefault(escape::EscapeIterInner::new(data, range))
} }
impl EscapeDefault { impl EscapeDefault {
pub(crate) fn empty() -> Self { #[inline]
let data = [Char::Null; 4]; pub(crate) const fn new(c: u8) -> Self {
EscapeDefault(escape::EscapeIterInner::new(data, 0..0)) Self(escape::EscapeIterInner::ascii(c))
} }
#[inline]
pub(crate) fn empty() -> Self {
Self(escape::EscapeIterInner::empty())
}
#[inline]
pub(crate) fn as_str(&self) -> &str { pub(crate) fn as_str(&self) -> &str {
self.0.as_str() self.0.as_str()
} }

View file

@ -449,10 +449,10 @@ impl char {
'\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark), '\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark),
'\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe), '\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe),
_ if args.escape_grapheme_extended && self.is_grapheme_extended() => { _ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
EscapeDebug::from_unicode(self.escape_unicode()) EscapeDebug::unicode(self)
} }
_ if is_printable(self) => EscapeDebug::printable(self), _ if is_printable(self) => EscapeDebug::printable(self),
_ => EscapeDebug::from_unicode(self.escape_unicode()), _ => EscapeDebug::unicode(self),
} }
} }
@ -555,9 +555,9 @@ impl char {
'\t' => EscapeDefault::backslash(ascii::Char::SmallT), '\t' => EscapeDefault::backslash(ascii::Char::SmallT),
'\r' => EscapeDefault::backslash(ascii::Char::SmallR), '\r' => EscapeDefault::backslash(ascii::Char::SmallR),
'\n' => EscapeDefault::backslash(ascii::Char::SmallN), '\n' => EscapeDefault::backslash(ascii::Char::SmallN),
'\\' | '\'' | '"' => EscapeDefault::backslash(self.as_ascii().unwrap()), '\\' | '\'' | '\"' => EscapeDefault::backslash(self.as_ascii().unwrap()),
'\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()), '\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()),
_ => EscapeDefault::from_unicode(self.escape_unicode()), _ => EscapeDefault::unicode(self),
} }
} }

View file

@ -152,10 +152,9 @@ pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
pub struct EscapeUnicode(escape::EscapeIterInner<10>); pub struct EscapeUnicode(escape::EscapeIterInner<10>);
impl EscapeUnicode { impl EscapeUnicode {
fn new(chr: char) -> Self { #[inline]
let mut data = [ascii::Char::Null; 10]; const fn new(c: char) -> Self {
let range = escape::escape_unicode_into(&mut data, chr); Self(escape::EscapeIterInner::unicode(c))
Self(escape::EscapeIterInner::new(data, range))
} }
} }
@ -219,18 +218,19 @@ impl fmt::Display for EscapeUnicode {
pub struct EscapeDefault(escape::EscapeIterInner<10>); pub struct EscapeDefault(escape::EscapeIterInner<10>);
impl EscapeDefault { impl EscapeDefault {
fn printable(chr: ascii::Char) -> Self { #[inline]
let data = [chr]; const fn printable(c: ascii::Char) -> Self {
Self(escape::EscapeIterInner::from_array(data)) Self(escape::EscapeIterInner::ascii(c.to_u8()))
} }
fn backslash(chr: ascii::Char) -> Self { #[inline]
let data = [ascii::Char::ReverseSolidus, chr]; const fn backslash(c: ascii::Char) -> Self {
Self(escape::EscapeIterInner::from_array(data)) Self(escape::EscapeIterInner::backslash(c))
} }
fn from_unicode(esc: EscapeUnicode) -> Self { #[inline]
Self(esc.0) const fn unicode(c: char) -> Self {
Self(escape::EscapeIterInner::unicode(c))
} }
} }
@ -304,23 +304,24 @@ enum EscapeDebugInner {
} }
impl EscapeDebug { impl EscapeDebug {
fn printable(chr: char) -> Self { #[inline]
const fn printable(chr: char) -> Self {
Self(EscapeDebugInner::Char(chr)) Self(EscapeDebugInner::Char(chr))
} }
fn backslash(chr: ascii::Char) -> Self { #[inline]
let data = [ascii::Char::ReverseSolidus, chr]; const fn backslash(c: ascii::Char) -> Self {
let iter = escape::EscapeIterInner::from_array(data); Self(EscapeDebugInner::Bytes(escape::EscapeIterInner::backslash(c)))
Self(EscapeDebugInner::Bytes(iter))
} }
fn from_unicode(esc: EscapeUnicode) -> Self { #[inline]
Self(EscapeDebugInner::Bytes(esc.0)) const fn unicode(c: char) -> Self {
Self(EscapeDebugInner::Bytes(escape::EscapeIterInner::unicode(c)))
} }
#[inline]
fn clear(&mut self) { fn clear(&mut self) {
let bytes = escape::EscapeIterInner::from_array([]); self.0 = EscapeDebugInner::Bytes(escape::EscapeIterInner::empty());
self.0 = EscapeDebugInner::Bytes(bytes);
} }
} }
@ -339,6 +340,7 @@ impl Iterator for EscapeDebug {
} }
} }
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len(); let n = self.len();
(n, Some(n)) (n, Some(n))

View file

@ -6,56 +6,79 @@ use crate::ops::Range;
const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap(); const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
/// Escapes a byte into provided buffer; returns length of escaped #[inline]
/// representation. const fn backslash<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u8>) {
pub(crate) fn escape_ascii_into(output: &mut [ascii::Char; 4], byte: u8) -> Range<u8> { const { assert!(N >= 2) };
#[inline]
fn backslash(a: ascii::Char) -> ([ascii::Char; 4], u8) {
([ascii::Char::ReverseSolidus, a, ascii::Char::Null, ascii::Char::Null], 2)
}
let (data, len) = match byte { let mut output = [ascii::Char::Null; N];
output[0] = ascii::Char::ReverseSolidus;
output[1] = a;
(output, 0..2)
}
/// Escapes an ASCII character.
///
/// Returns a buffer and the length of the escaped representation.
const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) {
const { assert!(N >= 4) };
match byte {
b'\t' => backslash(ascii::Char::SmallT), b'\t' => backslash(ascii::Char::SmallT),
b'\r' => backslash(ascii::Char::SmallR), b'\r' => backslash(ascii::Char::SmallR),
b'\n' => backslash(ascii::Char::SmallN), b'\n' => backslash(ascii::Char::SmallN),
b'\\' => backslash(ascii::Char::ReverseSolidus), b'\\' => backslash(ascii::Char::ReverseSolidus),
b'\'' => backslash(ascii::Char::Apostrophe), b'\'' => backslash(ascii::Char::Apostrophe),
b'\"' => backslash(ascii::Char::QuotationMark), b'\"' => backslash(ascii::Char::QuotationMark),
_ => { byte => {
if let Some(a) = byte.as_ascii() let mut output = [ascii::Char::Null; N];
if let Some(c) = byte.as_ascii()
&& !byte.is_ascii_control() && !byte.is_ascii_control()
{ {
([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1) output[0] = c;
(output, 0..1)
} else { } else {
let hi = HEX_DIGITS[usize::from(byte >> 4)]; let hi = HEX_DIGITS[(byte >> 4) as usize];
let lo = HEX_DIGITS[usize::from(byte & 0xf)]; let lo = HEX_DIGITS[(byte & 0xf) as usize];
([ascii::Char::ReverseSolidus, ascii::Char::SmallX, hi, lo], 4)
output[0] = ascii::Char::ReverseSolidus;
output[1] = ascii::Char::SmallX;
output[2] = hi;
output[3] = lo;
(output, 0..4)
} }
} }
}; }
*output = data;
0..len
} }
/// Escapes a character into provided buffer using `\u{NNNN}` representation. /// Escapes a character `\u{NNNN}` representation.
pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> Range<u8> { ///
/// Returns a buffer and the length of the escaped representation.
const fn escape_unicode<const N: usize>(c: char) -> ([ascii::Char; N], Range<u8>) {
const { assert!(N >= 10 && N < u8::MAX as usize) };
let c = u32::from(c);
// OR-ing `1` ensures that for `c == 0` the code computes that
// one digit should be printed.
let start = (c | 1).leading_zeros() as usize / 4 - 2;
let mut output = [ascii::Char::Null; N];
output[3] = HEX_DIGITS[((c >> 20) & 15) as usize];
output[4] = HEX_DIGITS[((c >> 16) & 15) as usize];
output[5] = HEX_DIGITS[((c >> 12) & 15) as usize];
output[6] = HEX_DIGITS[((c >> 8) & 15) as usize];
output[7] = HEX_DIGITS[((c >> 4) & 15) as usize];
output[8] = HEX_DIGITS[((c >> 0) & 15) as usize];
output[9] = ascii::Char::RightCurlyBracket; output[9] = ascii::Char::RightCurlyBracket;
output[start + 0] = ascii::Char::ReverseSolidus;
output[start + 1] = ascii::Char::SmallU;
output[start + 2] = ascii::Char::LeftCurlyBracket;
let ch = ch as u32; (output, (start as u8)..(N as u8))
output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize];
output[4] = HEX_DIGITS[((ch >> 16) & 15) as usize];
output[5] = HEX_DIGITS[((ch >> 12) & 15) as usize];
output[6] = HEX_DIGITS[((ch >> 8) & 15) as usize];
output[7] = HEX_DIGITS[((ch >> 4) & 15) as usize];
output[8] = HEX_DIGITS[((ch >> 0) & 15) as usize];
// or-ing 1 ensures that for ch==0 the code computes that one digit should
// be printed.
let start = (ch | 1).leading_zeros() as usize / 4 - 2;
const UNICODE_ESCAPE_PREFIX: &[ascii::Char; 3] = b"\\u{".as_ascii().unwrap();
output[start..][..3].copy_from_slice(UNICODE_ESCAPE_PREFIX);
(start as u8)..10
} }
/// An iterator over an fixed-size array. /// An iterator over an fixed-size array.
@ -65,45 +88,63 @@ pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> R
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct EscapeIterInner<const N: usize> { pub(crate) struct EscapeIterInner<const N: usize> {
// The element type ensures this is always ASCII, and thus also valid UTF-8. // The element type ensures this is always ASCII, and thus also valid UTF-8.
pub(crate) data: [ascii::Char; N], data: [ascii::Char; N],
// Invariant: alive.start <= alive.end <= N. // Invariant: `alive.start <= alive.end <= N`
pub(crate) alive: Range<u8>, alive: Range<u8>,
} }
impl<const N: usize> EscapeIterInner<N> { impl<const N: usize> EscapeIterInner<N> {
pub fn new(data: [ascii::Char; N], alive: Range<u8>) -> Self { pub const fn backslash(c: ascii::Char) -> Self {
const { assert!(N < 256) }; let (data, range) = backslash(c);
debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}"); Self { data, alive: range }
Self { data, alive }
} }
pub fn from_array<const M: usize>(array: [ascii::Char; M]) -> Self { pub const fn ascii(c: u8) -> Self {
const { assert!(M <= N) }; let (data, range) = escape_ascii(c);
Self { data, alive: range }
let mut data = [ascii::Char::Null; N];
data[..M].copy_from_slice(&array);
Self::new(data, 0..M as u8)
} }
pub const fn unicode(c: char) -> Self {
let (data, range) = escape_unicode(c);
Self { data, alive: range }
}
#[inline]
pub const fn empty() -> Self {
Self { data: [ascii::Char::Null; N], alive: 0..0 }
}
#[inline]
pub fn as_ascii(&self) -> &[ascii::Char] { pub fn as_ascii(&self) -> &[ascii::Char] {
&self.data[usize::from(self.alive.start)..usize::from(self.alive.end)] // SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`.
unsafe {
self.data.get_unchecked(usize::from(self.alive.start)..usize::from(self.alive.end))
}
} }
#[inline]
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
self.as_ascii().as_str() self.as_ascii().as_str()
} }
#[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
usize::from(self.alive.end - self.alive.start) usize::from(self.alive.end - self.alive.start)
} }
pub fn next(&mut self) -> Option<u8> { pub fn next(&mut self) -> Option<u8> {
self.alive.next().map(|i| self.data[usize::from(i)].to_u8()) let i = self.alive.next()?;
// SAFETY: `i` is guaranteed to be a valid index for `self.data`.
unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
} }
pub fn next_back(&mut self) -> Option<u8> { pub fn next_back(&mut self) -> Option<u8> {
self.alive.next_back().map(|i| self.data[usize::from(i)].to_u8()) let i = self.alive.next_back()?;
// SAFETY: `i` is guaranteed to be a valid index for `self.data`.
unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
} }
pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {

View file

@ -584,11 +584,11 @@ macro_rules! uint_impl {
// Thus, rather than using `overflowing_sub` that produces a wrapping // Thus, rather than using `overflowing_sub` that produces a wrapping
// subtraction, check it ourself so we can use an unchecked one. // subtraction, check it ourself so we can use an unchecked one.
if self >= rhs { if self < rhs {
None
} else {
// SAFETY: just checked this can't overflow // SAFETY: just checked this can't overflow
Some(unsafe { intrinsics::unchecked_sub(self, rhs) }) Some(unsafe { intrinsics::unchecked_sub(self, rhs) })
} else {
None
} }
} }

View file

@ -87,21 +87,18 @@ cfg_if::cfg_if! {
// /memory/aligned_memory.cc // /memory/aligned_memory.cc
libc::memalign(layout.align(), layout.size()) as *mut u8 libc::memalign(layout.align(), layout.size()) as *mut u8
} }
} else if #[cfg(target_os = "wasi")] {
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
// C11 aligned_alloc requires that the size be a multiple of the alignment.
// Layout already checks that the size rounded up doesn't overflow isize::MAX.
let align = layout.align();
let size = layout.size().next_multiple_of(align);
libc::aligned_alloc(align, size) as *mut u8
}
} else { } else {
#[inline] #[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
let mut out = ptr::null_mut(); let mut out = ptr::null_mut();
// posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. // We prefer posix_memalign over aligned_malloc since with aligned_malloc,
// Since these are all powers of 2, we can just use max. // implementations are making almost arbitrary choices for which alignments are
// "supported", making it hard to use. For instance, some implementations require the
// size to be a multiple of the alignment (wasi emmalloc), while others require the
// alignment to be at least the pointer size (Illumos, macOS) -- which may or may not be
// standards-compliant, but that does not help us.
// posix_memalign only has one, clear requirement: that the alignment be a multiple of
// `sizeof(void*)`. Since these are all powers of 2, we can just use max.
let align = layout.align().max(crate::mem::size_of::<usize>()); let align = layout.align().max(crate::mem::size_of::<usize>());
let ret = libc::posix_memalign(&mut out, align, layout.size()); let ret = libc::posix_memalign(&mut out, align, layout.size());
if ret != 0 { ptr::null_mut() } else { out as *mut u8 } if ret != 0 { ptr::null_mut() } else { out as *mut u8 }

View file

@ -8,6 +8,8 @@ compiler-docs = true
# where adding `debug!()` appears to do nothing. # where adding `debug!()` appears to do nothing.
# However, it makes running the compiler slightly slower. # However, it makes running the compiler slightly slower.
debug-logging = true debug-logging = true
# Get actually-useful information from backtraces, profiling, etc. with minimal added bytes
debuginfo-level = "line-tables-only"
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
incremental = true incremental = true
# Print backtrace on internal compiler errors during bootstrap # Print backtrace on internal compiler errors during bootstrap

View file

@ -26,7 +26,9 @@ use crate::core::build_steps::tool::{self, Tool};
use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection; use crate::core::config::TargetSelection;
use crate::utils::channel::{self, Info}; use crate::utils::channel::{self, Info};
use crate::utils::helpers::{exe, is_dylib, output, t, target_supports_cranelift_backend, timeit}; use crate::utils::helpers::{
exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit,
};
use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
@ -2024,7 +2026,7 @@ impl Step for Extended {
builder.run(&mut cmd); builder.run(&mut cmd);
if !builder.config.dry_run() { if !builder.config.dry_run() {
t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename))); t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
} }
} }
} }

View file

@ -12,7 +12,7 @@ use build_helper::ci::CiEnv;
use build_helper::stage0_parser::VersionMetadata; use build_helper::stage0_parser::VersionMetadata;
use xz2::bufread::XzDecoder; use xz2::bufread::XzDecoder;
use crate::utils::helpers::{check_run, exe, program_out_of_date}; use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date};
use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode}; use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode};
use crate::{t, Config}; use crate::{t, Config};
@ -209,7 +209,7 @@ impl Config {
None => panic!("no protocol in {url}"), None => panic!("no protocol in {url}"),
} }
t!( t!(
std::fs::rename(&tempfile, dest_path), move_file(&tempfile, dest_path),
format!("failed to rename {tempfile:?} to {dest_path:?}") format!("failed to rename {tempfile:?} to {dest_path:?}")
); );
} }
@ -313,7 +313,7 @@ impl Config {
if src_path.is_dir() && dst_path.exists() { if src_path.is_dir() && dst_path.exists() {
continue; continue;
} }
t!(fs::rename(src_path, dst_path)); t!(move_file(src_path, dst_path));
} }
let dst_dir = dst.join(directory_prefix); let dst_dir = dst.join(directory_prefix);
if dst_dir.exists() { if dst_dir.exists() {

View file

@ -180,4 +180,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
severity: ChangeSeverity::Info, severity: ChangeSeverity::Info,
summary: "New option `build.lldb` that will override the default lldb binary path used in debuginfo tests", summary: "New option `build.lldb` that will override the default lldb binary path used in debuginfo tests",
}, },
ChangeInfo {
change_id: 123337,
severity: ChangeSeverity::Info,
summary: r#"The compiler profile now defaults to rust.debuginfo-level = "line-tables-only""#,
},
]; ];

View file

@ -150,6 +150,21 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
} }
} }
/// Rename a file if from and to are in the same filesystem or
/// copy and remove the file otherwise
pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
match fs::rename(&from, &to) {
// FIXME: Once `ErrorKind::CrossesDevices` is stabilized use
// if e.kind() == io::ErrorKind::CrossesDevices {
#[cfg(unix)]
Err(e) if e.raw_os_error() == Some(libc::EXDEV) => {
std::fs::copy(&from, &to)?;
std::fs::remove_file(&from)
}
r => r,
}
}
pub fn forcing_clang_based_tests() -> bool { pub fn forcing_clang_based_tests() -> bool {
if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") { if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
match &var.to_string_lossy().to_lowercase()[..] { match &var.to_string_lossy().to_lowercase()[..] {

View file

@ -13,7 +13,7 @@ use std::{
use crate::core::builder::Builder; use crate::core::builder::Builder;
use crate::core::{build_steps::dist::distdir, builder::Kind}; use crate::core::{build_steps::dist::distdir, builder::Kind};
use crate::utils::channel; use crate::utils::channel;
use crate::utils::helpers::t; use crate::utils::helpers::{move_file, t};
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub(crate) enum OverlayKind { pub(crate) enum OverlayKind {
@ -284,7 +284,7 @@ impl<'a> Tarball<'a> {
// name, not "image". We rename the image directory just before passing // name, not "image". We rename the image directory just before passing
// into rust-installer. // into rust-installer.
let dest = self.temp_dir.join(self.package_name()); let dest = self.temp_dir.join(self.package_name());
t!(std::fs::rename(&self.image_dir, &dest)); t!(move_file(&self.image_dir, &dest));
self.run(|this, cmd| { self.run(|this, cmd| {
let distdir = distdir(this.builder); let distdir = distdir(this.builder);

View file

@ -40,6 +40,8 @@ include:
of a delimited expression, delimited expressions are generally combinable, of a delimited expression, delimited expressions are generally combinable,
regardless of the number of members. Previously only applied with exactly regardless of the number of members. Previously only applied with exactly
one member (except for closures with explicit blocks). one member (except for closures with explicit blocks).
- When line-breaking a binary operator, if the first operand spans multiple
lines, use the base indentation of the last line.
- Miscellaneous `rustfmt` bugfixes. - Miscellaneous `rustfmt` bugfixes.
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order). - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase". - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".

View file

@ -328,6 +328,37 @@ foo_bar
Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
than at other binary operators. than at other binary operators.
If line-breaking at a binary operator (including assignment operators) where the
first operand spans multiple lines, use the base indentation of the *last*
line of the first operand, and indent relative to that:
```rust
impl SomeType {
fn method(&mut self) {
self.array[array_index as usize]
.as_mut()
.expect("thing must exist")
.extra_info =
long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
self.array[array_index as usize]
.as_mut()
.expect("thing must exist")
.extra_info
+ long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
self.array[array_index as usize]
.as_mut()
.expect("thing must exist")
.extra_info = Some(ExtraInfo {
parent,
count: count as u16,
children: children.into_boxed_slice(),
});
}
}
```
### Casts (`as`) ### Casts (`as`)
Format `as` casts like a binary operator. In particular, always include spaces Format `as` casts like a binary operator. In particular, always include spaces

View file

@ -1424,6 +1424,10 @@ 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_.polarity != ty::ImplPolarity::Positive {
continue;
}
if !ty.is_doc_subtype_of(&impl_.for_, 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.
@ -1459,6 +1463,10 @@ 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_.polarity != ty::ImplPolarity::Positive {
continue;
}
if !ty.is_doc_subtype_of(&impl_.for_, 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.

View file

@ -2478,6 +2478,15 @@ impl<'test> TestCx<'test> {
} }
} }
let set_mir_dump_dir = |rustc: &mut Command| {
let mir_dump_dir = self.get_mir_dump_dir();
remove_and_create_dir_all(&mir_dump_dir);
let mut dir_opt = "-Zdump-mir-dir=".to_string();
dir_opt.push_str(mir_dump_dir.to_str().unwrap());
debug!("dir_opt: {:?}", dir_opt);
rustc.arg(dir_opt);
};
match self.config.mode { match self.config.mode {
Incremental => { Incremental => {
// If we are extracting and matching errors in the new // If we are extracting and matching errors in the new
@ -2532,13 +2541,7 @@ impl<'test> TestCx<'test> {
]); ]);
} }
let mir_dump_dir = self.get_mir_dump_dir(); set_mir_dump_dir(&mut rustc);
remove_and_create_dir_all(&mir_dump_dir);
let mut dir_opt = "-Zdump-mir-dir=".to_string();
dir_opt.push_str(mir_dump_dir.to_str().unwrap());
debug!("dir_opt: {:?}", dir_opt);
rustc.arg(dir_opt);
} }
CoverageMap => { CoverageMap => {
rustc.arg("-Cinstrument-coverage"); rustc.arg("-Cinstrument-coverage");
@ -2560,8 +2563,11 @@ impl<'test> TestCx<'test> {
Assembly | Codegen => { Assembly | Codegen => {
rustc.arg("-Cdebug-assertions=no"); rustc.arg("-Cdebug-assertions=no");
} }
Crashes => {
set_mir_dump_dir(&mut rustc);
}
RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake
| CodegenUnits | JsDocTest | Crashes => { | CodegenUnits | JsDocTest => {
// do not use JSON output // do not use JSON output
} }
} }

View file

@ -69,6 +69,10 @@ enum EnvironmentCmd {
#[arg(long, default_value = "opt-artifacts")] #[arg(long, default_value = "opt-artifacts")]
artifact_dir: Utf8PathBuf, artifact_dir: Utf8PathBuf,
/// Checkout directory of `rustc-perf`, it will be fetched automatically if unspecified.
#[arg(long)]
rustc_perf_checkout_dir: Option<Utf8PathBuf>,
/// Is LLVM for `rustc` built in shared library mode? /// Is LLVM for `rustc` built in shared library mode?
#[arg(long, default_value_t = true)] #[arg(long, default_value_t = true)]
llvm_shared: bool, llvm_shared: bool,
@ -109,6 +113,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
llvm_dir, llvm_dir,
python, python,
artifact_dir, artifact_dir,
rustc_perf_checkout_dir,
llvm_shared, llvm_shared,
use_bolt, use_bolt,
skipped_tests, skipped_tests,
@ -121,6 +126,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
.host_llvm_dir(llvm_dir) .host_llvm_dir(llvm_dir)
.artifact_dir(artifact_dir) .artifact_dir(artifact_dir)
.build_dir(checkout_dir) .build_dir(checkout_dir)
.prebuilt_rustc_perf(rustc_perf_checkout_dir)
.shared_llvm(llvm_shared) .shared_llvm(llvm_shared)
.use_bolt(use_bolt) .use_bolt(use_bolt)
.skipped_tests(skipped_tests) .skipped_tests(skipped_tests)

View file

@ -40,12 +40,17 @@ pub fn target() -> String {
/// Check if target is windows-like. /// Check if target is windows-like.
pub fn is_windows() -> bool { pub fn is_windows() -> bool {
env::var_os("IS_WINDOWS").is_some() target().contains("windows")
} }
/// Check if target uses msvc. /// Check if target uses msvc.
pub fn is_msvc() -> bool { pub fn is_msvc() -> bool {
env::var_os("IS_MSVC").is_some() target().contains("msvc")
}
/// Check if target uses macOS.
pub fn is_darwin() -> bool {
target().contains("darwin")
} }
/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a /// Construct a path to a static library under `$TMPDIR` given the library name. This will return a
@ -59,6 +64,12 @@ pub fn python_command() -> Command {
Command::new(python_path) Command::new(python_path)
} }
pub fn htmldocck() -> Command {
let mut python = python_command();
python.arg(source_path().join("src/etc/htmldocck.py"));
python
}
pub fn source_path() -> PathBuf { pub fn source_path() -> PathBuf {
std::env::var("S").expect("S variable does not exist").into() std::env::var("S").expect("S variable does not exist").into()
} }
@ -82,9 +93,47 @@ pub fn static_lib_name(name: &str) -> String {
// endif // endif
// endif // endif
// ``` // ```
assert!(!name.contains(char::is_whitespace), "name cannot contain whitespace"); assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
if target().contains("msvc") { format!("{name}.lib") } else { format!("lib{name}.a") } if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") }
}
/// Construct a path to a dynamic library under `$TMPDIR` given the library name. This will return a
/// path with `$TMPDIR` joined with platform-and-compiler-specific library name.
pub fn dynamic_lib(name: &str) -> PathBuf {
tmp_dir().join(dynamic_lib_name(name))
}
/// Construct the dynamic library name based on the platform.
pub fn dynamic_lib_name(name: &str) -> String {
// See tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifeq ($(UNAME),Darwin)
// DYLIB = $(TMPDIR)/lib$(1).dylib
// else
// ifdef IS_WINDOWS
// DYLIB = $(TMPDIR)/$(1).dll
// else
// DYLIB = $(TMPDIR)/lib$(1).so
// endif
// endif
// ```
assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
if is_darwin() {
format!("lib{name}.dylib")
} else if is_windows() {
format!("{name}.dll")
} else {
format!("lib{name}.so")
}
}
/// Construct a path to a rust library (rlib) under `$TMPDIR` given the library name. This will return a
/// path with `$TMPDIR` joined with the library name.
pub fn rust_lib(name: &str) -> PathBuf {
tmp_dir().join(format!("lib{name}.rlib"))
} }
/// Construct the binary name based on platform. /// Construct the binary name based on platform.

View file

@ -91,7 +91,7 @@ impl Rustc {
self self
} }
/// Specify path to the output file. /// Specify path to the output file. Equivalent to `-o`` in rustc.
pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.arg("-o"); self.cmd.arg("-o");
self.cmd.arg(path.as_ref()); self.cmd.arg(path.as_ref());
@ -150,6 +150,13 @@ impl Rustc {
self self
} }
/// Add a directory to the library search path. Equivalent to `-L`` in rustc.
pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.arg("-L");
self.cmd.arg(path.as_ref());
self
}
/// Specify the edition year. /// Specify the edition year.
pub fn edition(&mut self, edition: &str) -> &mut Self { pub fn edition(&mut self, edition: &str) -> &mut Self {
self.cmd.arg("--edition"); self.cmd.arg("--edition");

View file

@ -739,8 +739,8 @@ impl<'a> FmtVisitor<'a> {
(_, Const(..)) => Ordering::Greater, (_, Const(..)) => Ordering::Greater,
(MacCall(..), _) => Ordering::Less, (MacCall(..), _) => Ordering::Less,
(_, MacCall(..)) => Ordering::Greater, (_, MacCall(..)) => Ordering::Greater,
(Delegation(..), _) => Ordering::Less, (Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less,
(_, Delegation(..)) => Ordering::Greater, (_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater,
}); });
let mut prev_kind = None; let mut prev_kind = None;
for (buf, item) in buffer { for (buf, item) in buffer {

View file

@ -586,7 +586,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
); );
self.push_rewrite(item.span, rewrite); self.push_rewrite(item.span, rewrite);
} }
ast::ItemKind::Delegation(..) => { ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => {
// TODO: rewrite delegation items once syntax is established. // TODO: rewrite delegation items once syntax is established.
// For now, leave the contents of the Span unformatted. // For now, leave the contents of the Span unformatted.
self.push_rewrite(item.span, None) self.push_rewrite(item.span, None)

View file

@ -8,7 +8,6 @@ run-make/branch-protection-check-IBT/Makefile
run-make/c-dynamic-dylib/Makefile run-make/c-dynamic-dylib/Makefile
run-make/c-dynamic-rlib/Makefile run-make/c-dynamic-rlib/Makefile
run-make/c-link-to-rust-dylib/Makefile run-make/c-link-to-rust-dylib/Makefile
run-make/c-link-to-rust-staticlib/Makefile
run-make/c-static-dylib/Makefile run-make/c-static-dylib/Makefile
run-make/c-static-rlib/Makefile run-make/c-static-rlib/Makefile
run-make/c-unwind-abi-catch-lib-panic/Makefile run-make/c-unwind-abi-catch-lib-panic/Makefile
@ -94,8 +93,6 @@ run-make/invalid-staticlib/Makefile
run-make/issue-107094/Makefile run-make/issue-107094/Makefile
run-make/issue-10971-temps-dir/Makefile run-make/issue-10971-temps-dir/Makefile
run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-109934-lto-debuginfo/Makefile
run-make/issue-11908/Makefile
run-make/issue-14500/Makefile
run-make/issue-14698/Makefile run-make/issue-14698/Makefile
run-make/issue-15460/Makefile run-make/issue-15460/Makefile
run-make/issue-18943/Makefile run-make/issue-18943/Makefile
@ -181,7 +178,6 @@ run-make/native-link-modifier-whole-archive/Makefile
run-make/no-alloc-shim/Makefile run-make/no-alloc-shim/Makefile
run-make/no-builtins-attribute/Makefile run-make/no-builtins-attribute/Makefile
run-make/no-builtins-lto/Makefile run-make/no-builtins-lto/Makefile
run-make/no-cdylib-as-rdylib/Makefile
run-make/no-duplicate-libs/Makefile run-make/no-duplicate-libs/Makefile
run-make/no-intermediate-extras/Makefile run-make/no-intermediate-extras/Makefile
run-make/obey-crate-type-flag/Makefile run-make/obey-crate-type-flag/Makefile
@ -194,7 +190,6 @@ run-make/output-with-hyphens/Makefile
run-make/override-aliased-flags/Makefile run-make/override-aliased-flags/Makefile
run-make/overwrite-input/Makefile run-make/overwrite-input/Makefile
run-make/panic-abort-eh_frame/Makefile run-make/panic-abort-eh_frame/Makefile
run-make/panic-impl-transitive/Makefile
run-make/pass-linker-flags-flavor/Makefile run-make/pass-linker-flags-flavor/Makefile
run-make/pass-linker-flags-from-dep/Makefile run-make/pass-linker-flags-from-dep/Makefile
run-make/pass-linker-flags/Makefile run-make/pass-linker-flags/Makefile
@ -247,9 +242,7 @@ run-make/rustdoc-scrape-examples-multiple/Makefile
run-make/rustdoc-scrape-examples-remap/Makefile run-make/rustdoc-scrape-examples-remap/Makefile
run-make/rustdoc-scrape-examples-test/Makefile run-make/rustdoc-scrape-examples-test/Makefile
run-make/rustdoc-scrape-examples-whitespace/Makefile run-make/rustdoc-scrape-examples-whitespace/Makefile
run-make/rustdoc-themes/Makefile
run-make/rustdoc-verify-output-files/Makefile run-make/rustdoc-verify-output-files/Makefile
run-make/rustdoc-with-out-dir-option/Makefile
run-make/rustdoc-with-output-option/Makefile run-make/rustdoc-with-output-option/Makefile
run-make/rustdoc-with-short-out-dir-option/Makefile run-make/rustdoc-with-short-out-dir-option/Makefile
run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-cdylib-link/Makefile

View file

@ -1,16 +0,0 @@
# This test checks that C linking with Rust does not encounter any errors, with static libraries.
# See https://github.com/rust-lang/rust/issues/10434
# ignore-cross-compile
include ../tools.mk
# ignore-freebsd
# FIXME
all:
$(RUSTC) foo.rs
$(CC) bar.c $(call STATICLIB,foo) $(call OUT_EXE,bar) \
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,bar)
rm $(call STATICLIB,foo)
$(call RUN,bar)

View file

@ -0,0 +1,15 @@
// This test checks that C linking with Rust does not encounter any errors, with a static library.
// See https://github.com/rust-lang/rust/issues/10434
//@ ignore-cross-compile
use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
use std::fs;
fn main() {
rustc().input("foo.rs").run();
cc().input("bar.c").input(static_lib("foo")).out_exe("bar").args(&extra_c_flags()).run();
run("bar");
fs::remove_file(static_lib("foo"));
run("bar");
}

View file

@ -26,8 +26,7 @@ fn main() {
.arg("--test") .arg("--test")
.arg("--persist-doctests") .arg("--persist-doctests")
.arg(out_dir) .arg(out_dir)
.arg("--extern") .extern_("t", extern_path)
.arg(format!("t={}", extern_path.display()))
.run(); .run();
check_generated_binaries(); check_generated_binaries();
}); });
@ -38,8 +37,7 @@ fn main() {
.arg("--test") .arg("--test")
.arg("--persist-doctests") .arg("--persist-doctests")
.arg(out_dir) .arg(out_dir)
.arg("--extern") .extern_("t", extern_path)
.arg(format!("t={}", extern_path.display()))
.arg("--no-run") .arg("--no-run")
.run(); .run();
check_generated_binaries(); check_generated_binaries();
@ -59,8 +57,7 @@ fn main() {
.arg("doctests") .arg("doctests")
.arg("--test-run-directory") .arg("--test-run-directory")
.arg(run_dir) .arg(run_dir)
.arg("--extern") .extern_("t", "libt.rlib")
.arg("t=libt.rlib")
.run(); .run();
remove_dir_all(run_dir_path); remove_dir_all(run_dir_path);

View file

@ -29,8 +29,7 @@ fn main() {
.arg(run_dir_name) .arg(run_dir_name)
.arg("--runtool") .arg("--runtool")
.arg(&run_tool_binary) .arg(&run_tool_binary)
.arg("--extern") .extern_("t", "libt.rlib")
.arg("t=libt.rlib")
.current_dir(tmp_dir()) .current_dir(tmp_dir())
.run(); .run();

View file

@ -1,22 +0,0 @@
# ignore-cross-compile
# This test ensures that if you have the same rlib or dylib at two locations
# in the same path that you don't hit an assertion in the compiler.
#
# Note that this relies on `liburl` to be in the path somewhere else,
# and then our aux-built libraries will collide with liburl (they have
# the same version listed)
include ../tools.mk
all:
mkdir $(TMPDIR)/other
$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
mv $(call DYLIB,foo) $(TMPDIR)/other
$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
$(RUSTC) bar.rs -L $(TMPDIR)/other
rm -rf $(TMPDIR)
mkdir -p $(TMPDIR)/other
$(RUSTC) foo.rs --crate-type=rlib
mv $(TMPDIR)/libfoo.rlib $(TMPDIR)/other
$(RUSTC) foo.rs --crate-type=rlib
$(RUSTC) bar.rs -L $(TMPDIR)/other

View file

@ -1,15 +0,0 @@
include ../tools.mk
# ignore-cross-compile
# Test to make sure that reachable extern fns are always available in final
# productcs, including when LTO is used. In this test, the `foo` crate has a
# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate
# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
# only way that `foo.c` will successfully compile.
all:
$(RUSTC) foo.rs --crate-type=rlib
$(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a
$(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo)
$(call RUN,foo)

View file

@ -1,16 +0,0 @@
# ignore-cross-compile
include ../tools.mk
# Test that rustc will not attempt to link against a cdylib as if
# it is a rust dylib when an rlib for the same crate is available.
# Previously rustc didn't actually check if any further formats of
# a crate which has been loaded are of the same version and if
# they are actually valid. This caused a cdylib to be interpreted
# as rust dylib as soon as the corresponding rlib was loaded. As
# cdylibs don't export any rust symbols, linking would fail if
# rustc decides to link against the cdylib rather than the rlib.
all:
$(RUSTC) bar.rs --crate-type=rlib --crate-type=cdylib
$(RUSTC) foo.rs -C prefer-dynamic
$(call RUN,foo)

View file

@ -0,0 +1,16 @@
// This test produces an rlib and a cdylib from bar.rs.
// Then, foo.rs attempts to link to the bar library.
// If the test passes, that means rustc favored the rlib and ignored the cdylib.
// If the test fails, that is because the cdylib was picked, which does not export
// any Rust symbols.
// See https://github.com/rust-lang/rust/pull/113695
//@ ignore-cross-compile
use run_make_support::{run, rustc};
fn main() {
rustc().input("bar.rs").crate_type("rlib").crate_type("cdylib").run();
rustc().input("foo.rs").arg("-Cprefer-dynamic").run();
run("foo");
}

View file

@ -1,7 +0,0 @@
include ../tools.mk
# NOTE we use --emit=llvm-ir to avoid running the linker (linking will fail because there's no main
# in this crate)
all:
$(RUSTC) panic-impl-provider.rs
$(RUSTC) panic-impl-consumer.rs -C panic=abort --emit=llvm-ir -L $(TMPDIR)

View file

@ -0,0 +1,19 @@
// In Rust programs where the standard library is unavailable (#![no_std]), we may be interested
// in customizing how panics are handled. Here, the provider specifies that panics should be handled
// by entering an infinite loop. This test checks that this panic implementation can be transitively
// provided by an external crate.
// --emit=llvm-ir is used to avoid running the linker, as linking will fail due to the lack of main
// function in the crate.
// See https://github.com/rust-lang/rust/pull/50338
use run_make_support::{rustc, tmp_dir};
fn main() {
rustc().input("panic-impl-provider.rs").run();
rustc()
.input("panic-impl-consumer.rs")
.panic("abort")
.emit("llvm-ir")
.library_search_path(tmp_dir())
.run();
}

View file

@ -0,0 +1,26 @@
// Test to make sure that reachable extern fns are always available in final
// productcs, including when link time optimizations (LTO) are used.
// In this test, the `foo` crate has a reahable symbol,
// and is a dependency of the `bar` crate. When the `bar` crate
// is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
// only way that `foo.c` will successfully compile.
// See https://github.com/rust-lang/rust/issues/14500
//@ ignore-cross-compile
use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
fn main() {
let libbar_path = static_lib("bar");
rustc().input("foo.rs").crate_type("rlib").run();
rustc()
.input("bar.rs")
.crate_type("staticlib")
.arg("-Clto")
.library_search_path(".")
.output(&libbar_path)
.run();
cc().input("foo.c").input(libbar_path).args(&extra_c_flags()).out_exe("foo").run();
run("foo");
}

View file

@ -1,5 +1,4 @@
use run_make_support::{rustdoc, tmp_dir}; use run_make_support::{python_command, rustdoc, tmp_dir};
use std::process::Command;
fn main() { fn main() {
let out_dir = tmp_dir().join("out"); let out_dir = tmp_dir().join("out");
@ -10,6 +9,5 @@ fn main() {
.output(&out_dir) .output(&out_dir)
.run(); .run();
// FIXME (GuillaumeGomez): Port the python script to Rust as well. // FIXME (GuillaumeGomez): Port the python script to Rust as well.
let python = std::env::var("PYTHON").unwrap_or("python".into()); assert!(python_command().arg("validate_json.py").arg(&out_dir).status().unwrap().success());
assert!(Command::new(python).arg("validate_json.py").arg(&out_dir).status().unwrap().success());
} }

View file

@ -1,4 +1,4 @@
use run_make_support::{python_command, rustc, rustdoc, source_path, tmp_dir}; use run_make_support::{htmldocck, rustc, rustdoc, source_path, tmp_dir};
use std::fs::read_dir; use std::fs::read_dir;
use std::path::Path; use std::path::Path;
@ -45,11 +45,5 @@ fn main() {
} }
rustdoc.run(); rustdoc.run();
python_command() assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
.arg(source_path().join("/src/etc/htmldocck.py"))
.arg(out_dir)
.arg("src/lib.rs")
.status()
.unwrap()
.success();
} }

View file

@ -1,11 +0,0 @@
include ../tools.mk
# Test that rustdoc will properly load in a theme file and display it in the theme selector.
OUTPUT_DIR := "$(TMPDIR)/rustdoc-themes"
all:
awk '/Begin theme: light/ {in_theme=1;next} /End theme:/ {in_theme=0} { if (in_theme) print }' \
< '$(S)/src/librustdoc/html/static/css/noscript.css' > '$(TMPDIR)/test.css'
$(RUSTDOC) -o $(OUTPUT_DIR) foo.rs --theme $(TMPDIR)/test.css
$(HTMLDOCCK) $(OUTPUT_DIR) foo.rs

View file

@ -0,0 +1,31 @@
// Test that rustdoc will properly load in a theme file and display it in the theme selector.
use run_make_support::{htmldocck, rustdoc, source_path, tmp_dir};
fn main() {
let out_dir = tmp_dir().join("rustdoc-themes");
let test_css = out_dir.join("test.css");
let no_script =
std::fs::read_to_string(source_path().join("src/librustdoc/html/static/css/noscript.css"))
.unwrap();
let mut test_content = String::new();
let mut found_begin_light = false;
for line in no_script.split('\n') {
if line == "/* Begin theme: light */" {
found_begin_light = true;
} else if line == "/* End theme: light */" {
break;
} else if found_begin_light {
test_content.push_str(line);
test_content.push('\n');
}
}
assert!(!test_content.is_empty());
std::fs::create_dir_all(&out_dir).unwrap();
std::fs::write(&test_css, test_content).unwrap();
rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
assert!(htmldocck().arg(out_dir).arg("foo.rs").status().unwrap().success());
}

View file

@ -1,8 +0,0 @@
include ../tools.mk
OUTPUT_DIR := "$(TMPDIR)/rustdoc"
all:
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs

View file

@ -0,0 +1,7 @@
use run_make_support::{htmldocck, rustdoc, tmp_dir};
fn main() {
let out_dir = tmp_dir().join("rustdoc");
rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
}

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