mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
Merge pull request #4038 from rust-lang/rustup-2024-11-18
Automatic Rustup
This commit is contained in:
commit
00286e6a38
@ -3270,6 +3270,7 @@ name = "rustc_ast_lowering"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
@ -23,7 +23,7 @@ use crate::ast::*;
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, Token};
|
||||
use crate::tokenstream::*;
|
||||
use crate::visit::{AssocCtxt, BoundKind};
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt};
|
||||
|
||||
pub trait ExpectOne<A: Array> {
|
||||
fn expect_one(self, err: &'static str) -> A::Item;
|
||||
@ -37,7 +37,16 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
|
||||
}
|
||||
|
||||
pub trait WalkItemKind {
|
||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor);
|
||||
type Ctxt;
|
||||
fn walk(
|
||||
&mut self,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &mut Ident,
|
||||
visibility: &mut Visibility,
|
||||
ctxt: Self::Ctxt,
|
||||
visitor: &mut impl MutVisitor,
|
||||
);
|
||||
}
|
||||
|
||||
pub trait MutVisitor: Sized {
|
||||
@ -114,9 +123,9 @@ pub trait MutVisitor: Sized {
|
||||
fn flat_map_assoc_item(
|
||||
&mut self,
|
||||
i: P<AssocItem>,
|
||||
_ctxt: AssocCtxt,
|
||||
ctxt: AssocCtxt,
|
||||
) -> SmallVec<[P<AssocItem>; 1]> {
|
||||
walk_flat_map_item(self, i)
|
||||
walk_flat_map_assoc_item(self, i, ctxt)
|
||||
}
|
||||
|
||||
fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
|
||||
@ -880,7 +889,7 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
|
||||
|
||||
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||
match kind {
|
||||
FnKind::Fn(FnSig { header, decl, span }, generics, body) => {
|
||||
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
|
||||
// Identifier and visibility are visited as a part of the item.
|
||||
vis.visit_fn_header(header);
|
||||
vis.visit_generics(generics);
|
||||
@ -890,8 +899,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
FnKind::Closure(binder, decl, body) => {
|
||||
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||
vis.visit_closure_binder(binder);
|
||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||
vis.visit_fn_decl(decl);
|
||||
vis.visit_expr(body);
|
||||
}
|
||||
@ -1079,17 +1089,29 @@ pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_item_kind(
|
||||
kind: &mut impl WalkItemKind,
|
||||
pub fn walk_item_kind<K: WalkItemKind>(
|
||||
kind: &mut K,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &mut Ident,
|
||||
visibility: &mut Visibility,
|
||||
ctxt: K::Ctxt,
|
||||
vis: &mut impl MutVisitor,
|
||||
) {
|
||||
kind.walk(span, id, vis)
|
||||
kind.walk(span, id, ident, visibility, ctxt, vis)
|
||||
}
|
||||
|
||||
impl WalkItemKind for ItemKind {
|
||||
fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) {
|
||||
type Ctxt = ();
|
||||
fn walk(
|
||||
&mut self,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &mut Ident,
|
||||
visibility: &mut Visibility,
|
||||
_ctxt: Self::Ctxt,
|
||||
vis: &mut impl MutVisitor,
|
||||
) {
|
||||
match self {
|
||||
ItemKind::ExternCrate(_orig_name) => {}
|
||||
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
||||
@ -1102,7 +1124,11 @@ impl WalkItemKind for ItemKind {
|
||||
}
|
||||
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(vis, defaultness);
|
||||
vis.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
||||
vis.visit_fn(
|
||||
FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
|
||||
span,
|
||||
id,
|
||||
);
|
||||
}
|
||||
ItemKind::Mod(safety, mod_kind) => {
|
||||
visit_safety(vis, safety);
|
||||
@ -1201,14 +1227,27 @@ impl WalkItemKind for ItemKind {
|
||||
}
|
||||
|
||||
impl WalkItemKind for AssocItemKind {
|
||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
|
||||
type Ctxt = AssocCtxt;
|
||||
fn walk(
|
||||
&mut self,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &mut Ident,
|
||||
visibility: &mut Visibility,
|
||||
ctxt: Self::Ctxt,
|
||||
visitor: &mut impl MutVisitor,
|
||||
) {
|
||||
match self {
|
||||
AssocItemKind::Const(item) => {
|
||||
visit_const_item(item, visitor);
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(visitor, defaultness);
|
||||
visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
||||
visitor.visit_fn(
|
||||
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
|
||||
span,
|
||||
id,
|
||||
);
|
||||
}
|
||||
AssocItemKind::Type(box TyAlias {
|
||||
defaultness,
|
||||
@ -1288,24 +1327,40 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
|
||||
vis.visit_span(inject_use_span);
|
||||
}
|
||||
|
||||
/// Mutates one item, returning the item again.
|
||||
pub fn walk_flat_map_item<K: WalkItemKind>(
|
||||
pub fn walk_flat_map_item<K: WalkItemKind<Ctxt = ()>>(
|
||||
visitor: &mut impl MutVisitor,
|
||||
item: P<Item<K>>,
|
||||
) -> SmallVec<[P<Item<K>>; 1]> {
|
||||
walk_flat_map_assoc_item(visitor, item, ())
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_assoc_item<K: WalkItemKind>(
|
||||
visitor: &mut impl MutVisitor,
|
||||
mut item: P<Item<K>>,
|
||||
ctxt: K::Ctxt,
|
||||
) -> SmallVec<[P<Item<K>>; 1]> {
|
||||
let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
|
||||
visitor.visit_id(id);
|
||||
visit_attrs(visitor, attrs);
|
||||
visitor.visit_vis(vis);
|
||||
visitor.visit_ident(ident);
|
||||
kind.walk(*span, *id, visitor);
|
||||
kind.walk(*span, *id, ident, vis, ctxt, visitor);
|
||||
visit_lazy_tts(visitor, tokens);
|
||||
visitor.visit_span(span);
|
||||
smallvec![item]
|
||||
}
|
||||
|
||||
impl WalkItemKind for ForeignItemKind {
|
||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
|
||||
type Ctxt = ();
|
||||
fn walk(
|
||||
&mut self,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &mut Ident,
|
||||
visibility: &mut Visibility,
|
||||
_ctxt: Self::Ctxt,
|
||||
visitor: &mut impl MutVisitor,
|
||||
) {
|
||||
match self {
|
||||
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
||||
visitor.visit_ty(ty);
|
||||
@ -1313,7 +1368,11 @@ impl WalkItemKind for ForeignItemKind {
|
||||
}
|
||||
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||
visit_defaultness(visitor, defaultness);
|
||||
visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
||||
visitor.visit_fn(
|
||||
FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
|
||||
span,
|
||||
id,
|
||||
);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
@ -1522,9 +1581,8 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
||||
fn_arg_span,
|
||||
}) => {
|
||||
visit_constness(vis, constness);
|
||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||
vis.visit_capture_by(capture_clause);
|
||||
vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id);
|
||||
vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
|
||||
vis.visit_span(fn_decl_span);
|
||||
vis.visit_span(fn_arg_span);
|
||||
}
|
||||
@ -1785,8 +1843,20 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
|
||||
#[derive(Debug)]
|
||||
pub enum FnKind<'a> {
|
||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||
Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>),
|
||||
Fn(
|
||||
FnCtxt,
|
||||
&'a mut Ident,
|
||||
&'a mut FnSig,
|
||||
&'a mut Visibility,
|
||||
&'a mut Generics,
|
||||
&'a mut Option<P<Block>>,
|
||||
),
|
||||
|
||||
/// E.g., `|x, y| body`.
|
||||
Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>),
|
||||
Closure(
|
||||
&'a mut ClosureBinder,
|
||||
&'a mut Option<CoroutineKind>,
|
||||
&'a mut P<FnDecl>,
|
||||
&'a mut P<Expr>,
|
||||
),
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ impl BoundKind {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum FnKind<'a> {
|
||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
|
||||
Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
|
||||
|
||||
/// E.g., `|x, y| body`.
|
||||
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
|
||||
@ -112,11 +112,15 @@ pub enum LifetimeCtxt {
|
||||
GenericArg,
|
||||
}
|
||||
|
||||
pub trait WalkItemKind: Sized {
|
||||
pub trait WalkItemKind {
|
||||
type Ctxt;
|
||||
fn walk<'a, V: Visitor<'a>>(
|
||||
&'a self,
|
||||
item: &'a Item<Self>,
|
||||
ctxt: AssocCtxt,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &'a Ident,
|
||||
visibility: &'a Visibility,
|
||||
ctxt: Self::Ctxt,
|
||||
visitor: &mut V,
|
||||
) -> V::Result;
|
||||
}
|
||||
@ -268,8 +272,8 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result {
|
||||
walk_fn_ret_ty(self, ret_ty)
|
||||
}
|
||||
fn visit_fn_header(&mut self, _header: &'ast FnHeader) -> Self::Result {
|
||||
Self::Result::output()
|
||||
fn visit_fn_header(&mut self, header: &'ast FnHeader) -> Self::Result {
|
||||
walk_fn_header(self, header)
|
||||
}
|
||||
fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result {
|
||||
walk_expr_field(self, f)
|
||||
@ -292,6 +296,9 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result {
|
||||
Self::Result::output()
|
||||
}
|
||||
fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result {
|
||||
Self::Result::output()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
|
||||
@ -337,16 +344,19 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR
|
||||
}
|
||||
|
||||
impl WalkItemKind for ItemKind {
|
||||
type Ctxt = ();
|
||||
fn walk<'a, V: Visitor<'a>>(
|
||||
&'a self,
|
||||
item: &'a Item<Self>,
|
||||
_ctxt: AssocCtxt,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &'a Ident,
|
||||
vis: &'a Visibility,
|
||||
_ctxt: Self::Ctxt,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
let Item { id, span, vis, ident, .. } = item;
|
||||
match self {
|
||||
ItemKind::ExternCrate(_rename) => {}
|
||||
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)),
|
||||
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)),
|
||||
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
@ -357,8 +367,8 @@ impl WalkItemKind for ItemKind {
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref());
|
||||
try_visit!(visitor.visit_fn(kind, *span, *id));
|
||||
let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
|
||||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _inline, _inner_span) => {
|
||||
@ -415,7 +425,7 @@ impl WalkItemKind for ItemKind {
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||
}
|
||||
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
||||
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)),
|
||||
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, id)),
|
||||
ItemKind::Delegation(box Delegation {
|
||||
id,
|
||||
qself,
|
||||
@ -431,7 +441,7 @@ impl WalkItemKind for ItemKind {
|
||||
}
|
||||
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||
try_visit!(walk_qself(visitor, qself));
|
||||
try_visit!(visitor.visit_path(prefix, *id));
|
||||
try_visit!(visitor.visit_path(prefix, id));
|
||||
if let Some(suffixes) = suffixes {
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(ident);
|
||||
@ -449,9 +459,9 @@ impl WalkItemKind for ItemKind {
|
||||
|
||||
pub fn walk_item<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
item: &'a Item<impl WalkItemKind>,
|
||||
item: &'a Item<impl WalkItemKind<Ctxt = ()>>,
|
||||
) -> V::Result {
|
||||
walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/)
|
||||
walk_assoc_item(visitor, item, ())
|
||||
}
|
||||
|
||||
pub fn walk_enum_def<'a, V: Visitor<'a>>(
|
||||
@ -681,20 +691,23 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
||||
}
|
||||
|
||||
impl WalkItemKind for ForeignItemKind {
|
||||
type Ctxt = ();
|
||||
fn walk<'a, V: Visitor<'a>>(
|
||||
&'a self,
|
||||
item: &'a Item<Self>,
|
||||
_ctxt: AssocCtxt,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &'a Ident,
|
||||
vis: &'a Visibility,
|
||||
_ctxt: Self::Ctxt,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
let &Item { id, span, ident, ref vis, .. } = item;
|
||||
match self {
|
||||
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
|
||||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
@ -813,6 +826,12 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy)
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result {
|
||||
let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header;
|
||||
visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_fn_decl<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
FnDecl { inputs, output }: &'a FnDecl,
|
||||
@ -830,8 +849,9 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
|
||||
try_visit!(walk_fn_decl(visitor, decl));
|
||||
visit_opt!(visitor, visit_block, body);
|
||||
}
|
||||
FnKind::Closure(binder, _coroutine_kind, decl, body) => {
|
||||
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||
try_visit!(visitor.visit_closure_binder(binder));
|
||||
visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
|
||||
try_visit!(walk_fn_decl(visitor, decl));
|
||||
try_visit!(visitor.visit_expr(body));
|
||||
}
|
||||
@ -840,13 +860,16 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
|
||||
}
|
||||
|
||||
impl WalkItemKind for AssocItemKind {
|
||||
type Ctxt = AssocCtxt;
|
||||
fn walk<'a, V: Visitor<'a>>(
|
||||
&'a self,
|
||||
item: &'a Item<Self>,
|
||||
ctxt: AssocCtxt,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
ident: &'a Ident,
|
||||
vis: &'a Visibility,
|
||||
ctxt: Self::Ctxt,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
let &Item { id, span, ident, ref vis, .. } = item;
|
||||
match self {
|
||||
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
@ -854,8 +877,7 @@ impl WalkItemKind for AssocItemKind {
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||
let kind =
|
||||
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
|
||||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
AssocItemKind::Type(box TyAlias {
|
||||
@ -903,16 +925,16 @@ impl WalkItemKind for AssocItemKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_assoc_item<'a, V: Visitor<'a>>(
|
||||
pub fn walk_assoc_item<'a, V: Visitor<'a>, K: WalkItemKind>(
|
||||
visitor: &mut V,
|
||||
item: &'a Item<impl WalkItemKind>,
|
||||
ctxt: AssocCtxt,
|
||||
item: &'a Item<K>,
|
||||
ctxt: K::Ctxt,
|
||||
) -> V::Result {
|
||||
let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item;
|
||||
let Item { id, span, ident, vis, attrs, kind, tokens: _ } = item;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(kind.walk(item, ctxt, visitor));
|
||||
try_visit!(kind.walk(*span, *id, ident, vis, ctxt, visitor));
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ doctest = false
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
|
@ -103,6 +103,12 @@ ast_lowering_invalid_asm_template_modifier_reg_class =
|
||||
ast_lowering_invalid_asm_template_modifier_sym =
|
||||
asm template modifiers are not allowed for `sym` arguments
|
||||
|
||||
ast_lowering_invalid_legacy_const_generic_arg =
|
||||
invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
|
||||
|
||||
ast_lowering_invalid_legacy_const_generic_arg_suggestion =
|
||||
try using a const generic argument instead
|
||||
|
||||
ast_lowering_invalid_register =
|
||||
invalid register `{$reg}`: {$error}
|
||||
|
||||
|
@ -451,3 +451,26 @@ pub(crate) struct YieldInClosure {
|
||||
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_legacy_const_generic_arg)]
|
||||
pub(crate) struct InvalidLegacyConstGenericArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: UseConstGenericArg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
ast_lowering_invalid_legacy_const_generic_arg_suggestion,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub(crate) struct UseConstGenericArg {
|
||||
#[suggestion_part(code = "::<{const_args}>")]
|
||||
pub end_of_fn: Span,
|
||||
pub const_args: String,
|
||||
pub other_args: String,
|
||||
#[suggestion_part(code = "{other_args}")]
|
||||
pub call_args: Span,
|
||||
}
|
||||
|
@ -1,18 +1,22 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_ast::ptr::P as AstP;
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::source_map::{Spanned, respan};
|
||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use visit::{Visitor, walk_expr};
|
||||
|
||||
use super::errors::{
|
||||
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
||||
@ -23,9 +27,32 @@ use super::errors::{
|
||||
use super::{
|
||||
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
use crate::errors::YieldInClosure;
|
||||
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
||||
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated};
|
||||
|
||||
struct WillCreateDefIdsVisitor {}
|
||||
|
||||
impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
|
||||
type Result = ControlFlow<Span>;
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
|
||||
ControlFlow::Break(c.value.span)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'v Item) -> Self::Result {
|
||||
ControlFlow::Break(item.span)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {
|
||||
match ex.kind {
|
||||
ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => {
|
||||
ControlFlow::Break(ex.span)
|
||||
}
|
||||
_ => walk_expr(self, ex),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
|
||||
@ -396,10 +423,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let mut error = None;
|
||||
let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| {
|
||||
// Avoid emitting the error multiple times.
|
||||
if error.is_none() {
|
||||
let mut const_args = vec![];
|
||||
let mut other_args = vec![];
|
||||
for (idx, arg) in args.iter().enumerate() {
|
||||
if legacy_args_idx.contains(&idx) {
|
||||
const_args.push(format!("{{ {} }}", expr_to_string(arg)));
|
||||
} else {
|
||||
other_args.push(expr_to_string(arg));
|
||||
}
|
||||
}
|
||||
let suggestion = UseConstGenericArg {
|
||||
end_of_fn: f.span.shrink_to_hi(),
|
||||
const_args: const_args.join(", "),
|
||||
other_args: other_args.join(", "),
|
||||
call_args: args[0].span.to(args.last().unwrap().span),
|
||||
};
|
||||
error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion }));
|
||||
}
|
||||
error.unwrap()
|
||||
};
|
||||
|
||||
// Split the arguments into const generics and normal arguments
|
||||
let mut real_args = vec![];
|
||||
let mut generic_args = ThinVec::new();
|
||||
for (idx, arg) in args.into_iter().enumerate() {
|
||||
for (idx, arg) in args.iter().cloned().enumerate() {
|
||||
if legacy_args_idx.contains(&idx) {
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let node_id = self.next_node_id();
|
||||
@ -410,7 +461,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
|
||||
}
|
||||
|
||||
let anon_const = AnonConst { id: node_id, value: arg };
|
||||
let mut visitor = WillCreateDefIdsVisitor {};
|
||||
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
|
||||
AstP(Expr {
|
||||
id: self.next_node_id(),
|
||||
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
|
||||
span: f.span,
|
||||
attrs: [].into(),
|
||||
tokens: None,
|
||||
})
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
|
||||
let anon_const = AnonConst { id: node_id, value: const_value };
|
||||
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
|
||||
} else {
|
||||
real_args.push(arg);
|
||||
|
@ -738,7 +738,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||
) -> Span {
|
||||
self.tcx.with_stable_hashing_context(|hcx| {
|
||||
span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx)
|
||||
span.mark_with_reason(allow_internal_unstable, reason, span.edition(), hcx)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -946,8 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(&item.ident);
|
||||
let kind =
|
||||
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
|
||||
let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return; // Avoid visiting again.
|
||||
@ -1476,14 +1475,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
{
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(&item.ident);
|
||||
let kind = FnKind::Fn(
|
||||
FnCtxt::Assoc(ctxt),
|
||||
item.ident,
|
||||
sig,
|
||||
&item.vis,
|
||||
generics,
|
||||
body.as_deref(),
|
||||
);
|
||||
let kind =
|
||||
FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
}
|
||||
|
@ -1,93 +1,171 @@
|
||||
use std::fmt;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges};
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
|
||||
};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::fmt::DebugWithContext;
|
||||
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
||||
use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable};
|
||||
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
|
||||
|
||||
/// The results of the dataflow analyses used by the borrow checker.
|
||||
pub(crate) struct BorrowckResults<'a, 'tcx> {
|
||||
pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>,
|
||||
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>,
|
||||
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>,
|
||||
// This analysis is different to most others. Its results aren't computed with
|
||||
// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
|
||||
// computed individually with `iterate_to_fixpoint`.
|
||||
pub(crate) struct Borrowck<'a, 'tcx> {
|
||||
pub(crate) borrows: Borrows<'a, 'tcx>,
|
||||
pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>,
|
||||
pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
||||
|
||||
const NAME: &'static str = "borrowck";
|
||||
|
||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
||||
BorrowckDomain {
|
||||
borrows: self.borrows.bottom_value(body),
|
||||
uninits: self.uninits.bottom_value(body),
|
||||
ever_inits: self.ever_inits.bottom_value(body),
|
||||
}
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) {
|
||||
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn apply_before_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn apply_before_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &'mir mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
self.borrows.apply_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
|
||||
// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
|
||||
// analysis doesn't use.
|
||||
TerminatorEdges::None
|
||||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
_state: &mut Self::Domain,
|
||||
_block: BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn apply_switch_int_edge_effects(
|
||||
&mut self,
|
||||
_block: BasicBlock,
|
||||
_discr: &mir::Operand<'tcx>,
|
||||
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
||||
) {
|
||||
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
impl JoinSemiLattice for BorrowckDomain<'_, '_> {
|
||||
fn join(&mut self, _other: &Self) -> bool {
|
||||
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx>
|
||||
where
|
||||
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
|
||||
{
|
||||
fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("borrows: ")?;
|
||||
self.borrows.fmt_with(ctxt, f)?;
|
||||
f.write_str(" uninits: ")?;
|
||||
self.uninits.fmt_with(ctxt, f)?;
|
||||
f.write_str(" ever_inits: ")?;
|
||||
self.ever_inits.fmt_with(ctxt, f)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self == old {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.borrows != old.borrows {
|
||||
f.write_str("borrows: ")?;
|
||||
self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
|
||||
if self.uninits != old.uninits {
|
||||
f.write_str("uninits: ")?;
|
||||
self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
|
||||
if self.ever_inits != old.ever_inits {
|
||||
f.write_str("ever_inits: ")?;
|
||||
self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The transient state of the dataflow analyses used by the borrow checker.
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct BorrowckDomain<'a, 'tcx> {
|
||||
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
|
||||
type Direction = Forward;
|
||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
||||
|
||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
||||
BorrowckDomain {
|
||||
borrows: self.borrows.analysis.bottom_value(body),
|
||||
uninits: self.uninits.analysis.bottom_value(body),
|
||||
ever_inits: self.ever_inits.analysis.bottom_value(body),
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
|
||||
state.borrows.clone_from(self.borrows.entry_set_for_block(block));
|
||||
state.uninits.clone_from(self.uninits.entry_set_for_block(block));
|
||||
state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block));
|
||||
}
|
||||
|
||||
fn reconstruct_before_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_before_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
#[orderable]
|
||||
#[debug_format = "bw{}"]
|
||||
|
@ -36,13 +36,13 @@ use rustc_middle::mir::*;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::Analysis;
|
||||
use rustc_mir_dataflow::impls::{
|
||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||
};
|
||||
use rustc_mir_dataflow::move_paths::{
|
||||
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::UNUSED_MUT;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
@ -50,7 +50,7 @@ use tracing::{debug, instrument};
|
||||
|
||||
use crate::borrow_set::{BorrowData, BorrowSet};
|
||||
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
||||
use crate::dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows};
|
||||
use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
|
||||
use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
|
||||
use crate::location::LocationTable;
|
||||
use crate::nll::PoloniusOutput;
|
||||
@ -221,6 +221,10 @@ fn do_mir_borrowck<'tcx>(
|
||||
consumer_options,
|
||||
);
|
||||
|
||||
// `flow_inits` is large, so we drop it as soon as possible. This reduces
|
||||
// peak memory usage significantly on some benchmarks.
|
||||
drop(flow_inits);
|
||||
|
||||
// Dump MIR results into a file, if that is enabled. This let us
|
||||
// write unit-tests, as well as helping with debugging.
|
||||
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
|
||||
@ -229,27 +233,6 @@ fn do_mir_borrowck<'tcx>(
|
||||
// information.
|
||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, &opaque_type_values, diags);
|
||||
|
||||
// The various `flow_*` structures can be large. We drop `flow_inits` here
|
||||
// so it doesn't overlap with the others below. This reduces peak memory
|
||||
// usage significantly on some benchmarks.
|
||||
drop(flow_inits);
|
||||
|
||||
let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint(
|
||||
tcx,
|
||||
body,
|
||||
Some("borrowck"),
|
||||
);
|
||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
|
||||
tcx,
|
||||
body,
|
||||
Some("borrowck"),
|
||||
);
|
||||
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
|
||||
tcx,
|
||||
body,
|
||||
Some("borrowck"),
|
||||
);
|
||||
|
||||
let movable_coroutine =
|
||||
// The first argument is the coroutine type passed by value
|
||||
if let Some(local) = body.local_decls.raw.get(1)
|
||||
@ -334,16 +317,11 @@ fn do_mir_borrowck<'tcx>(
|
||||
// Compute and report region errors, if any.
|
||||
mbcx.report_region_errors(nll_errors);
|
||||
|
||||
let mut results = BorrowckResults {
|
||||
ever_inits: flow_ever_inits,
|
||||
uninits: flow_uninits,
|
||||
borrows: flow_borrows,
|
||||
};
|
||||
|
||||
rustc_mir_dataflow::visit_results(
|
||||
let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
|
||||
visit_results(
|
||||
body,
|
||||
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
||||
&mut results,
|
||||
&mut flow_results,
|
||||
&mut mbcx,
|
||||
);
|
||||
|
||||
@ -426,6 +404,47 @@ fn do_mir_borrowck<'tcx>(
|
||||
(result, body_with_facts)
|
||||
}
|
||||
|
||||
fn get_flow_results<'a, 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
move_data: &'a MoveData<'tcx>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
) -> Results<'tcx, Borrowck<'a, 'tcx>> {
|
||||
// We compute these three analyses individually, but them combine them into
|
||||
// a single results so that `mbcx` can visit them all together.
|
||||
let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
|
||||
tcx,
|
||||
body,
|
||||
Some("borrowck"),
|
||||
);
|
||||
let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
|
||||
tcx,
|
||||
body,
|
||||
Some("borrowck"),
|
||||
);
|
||||
let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
|
||||
tcx,
|
||||
body,
|
||||
Some("borrowck"),
|
||||
);
|
||||
|
||||
let analysis = Borrowck {
|
||||
borrows: borrows.analysis,
|
||||
uninits: uninits.analysis,
|
||||
ever_inits: ever_inits.analysis,
|
||||
};
|
||||
|
||||
assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len());
|
||||
assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len());
|
||||
let entry_sets: EntrySets<'_, Borrowck<'_, '_>> =
|
||||
itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets)
|
||||
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
|
||||
.collect();
|
||||
|
||||
Results { analysis, entry_sets }
|
||||
}
|
||||
|
||||
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
||||
pub(crate) infcx: InferCtxt<'tcx>,
|
||||
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
||||
@ -588,14 +607,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||
// 2. loans made in overlapping scopes do not conflict
|
||||
// 3. assignments do not affect things loaned out as immutable
|
||||
// 4. moves do not affect things loaned out in any way
|
||||
impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||
for MirBorrowckCtxt<'a, '_, 'tcx>
|
||||
{
|
||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
||||
|
||||
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||
fn visit_statement_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
stmt: &'a Statement<'tcx>,
|
||||
location: Location,
|
||||
@ -667,7 +682,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
term: &'a Terminator<'tcx>,
|
||||
loc: Location,
|
||||
@ -780,7 +795,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
term: &'a Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
@ -204,10 +204,10 @@ impl MutVisitor for CfgEval<'_> {
|
||||
fn flat_map_assoc_item(
|
||||
&mut self,
|
||||
item: P<ast::AssocItem>,
|
||||
_ctxt: AssocCtxt,
|
||||
ctxt: AssocCtxt,
|
||||
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||
let item = configure!(self, item);
|
||||
mut_visit::walk_flat_map_item(self, item)
|
||||
mut_visit::walk_flat_map_assoc_item(self, item, ctxt)
|
||||
}
|
||||
|
||||
fn flat_map_foreign_item(
|
||||
|
@ -144,7 +144,15 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||
item.kind
|
||||
{
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
walk_item_kind(&mut item.kind, item.span, item.id, self);
|
||||
walk_item_kind(
|
||||
&mut item.kind,
|
||||
item.span,
|
||||
item.id,
|
||||
&mut item.ident,
|
||||
&mut item.vis,
|
||||
(),
|
||||
self,
|
||||
);
|
||||
self.add_test_cases(item.id, span, prev_tests);
|
||||
} else {
|
||||
// But in those cases, we emit a lint to warn the user of these missing tests.
|
||||
|
@ -453,11 +453,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||
fx.bcx.ins().trap(TrapCode::user(2).unwrap());
|
||||
return Ok(());
|
||||
}
|
||||
sym::likely | sym::unlikely => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
ret.write_cvalue(fx, a);
|
||||
}
|
||||
sym::breakpoint => {
|
||||
intrinsic_args!(fx, args => (); intrinsic);
|
||||
|
||||
@ -1267,6 +1262,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||
);
|
||||
}
|
||||
|
||||
sym::cold_path => {
|
||||
// This is a no-op. The intrinsic is just a hint to the optimizer.
|
||||
}
|
||||
|
||||
// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
|
||||
// by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`.
|
||||
_ => {
|
||||
|
@ -139,8 +139,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
sym::likely => self.expect(args[0].immediate(), true),
|
||||
sym::unlikely => self.expect(args[0].immediate(), false),
|
||||
sym::is_val_statically_known => {
|
||||
let a = args[0].immediate();
|
||||
let builtin = self.context.get_builtin_function("__builtin_constant_p");
|
||||
|
@ -192,7 +192,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
Some(instance),
|
||||
)
|
||||
}
|
||||
sym::likely => self.expect(args[0].immediate(), true),
|
||||
sym::is_val_statically_known => {
|
||||
let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx);
|
||||
let kind = self.type_kind(intrinsic_type);
|
||||
@ -213,7 +212,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
self.const_bool(false)
|
||||
}
|
||||
}
|
||||
sym::unlikely => self.expect(args[0].immediate(), false),
|
||||
sym::select_unpredictable => {
|
||||
let cond = args[0].immediate();
|
||||
assert_eq!(args[1].layout, args[2].layout);
|
||||
|
@ -377,20 +377,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
// If there are two targets (one conditional, one fallback), emit `br` instead of
|
||||
// `switch`.
|
||||
let (test_value, target) = target_iter.next().unwrap();
|
||||
let lltrue = helper.llbb_with_cleanup(self, target);
|
||||
let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
|
||||
let otherwise = targets.otherwise();
|
||||
let lltarget = helper.llbb_with_cleanup(self, target);
|
||||
let llotherwise = helper.llbb_with_cleanup(self, otherwise);
|
||||
let target_cold = self.cold_blocks[target];
|
||||
let otherwise_cold = self.cold_blocks[otherwise];
|
||||
// If `target_cold == otherwise_cold`, the branches have the same weight
|
||||
// so there is no expectation. If they differ, the `target` branch is expected
|
||||
// when the `otherwise` branch is cold.
|
||||
let expect = if target_cold == otherwise_cold { None } else { Some(otherwise_cold) };
|
||||
if switch_ty == bx.tcx().types.bool {
|
||||
// Don't generate trivial icmps when switching on bool.
|
||||
match test_value {
|
||||
0 => bx.cond_br(discr_value, llfalse, lltrue),
|
||||
1 => bx.cond_br(discr_value, lltrue, llfalse),
|
||||
0 => {
|
||||
let expect = expect.map(|e| !e);
|
||||
bx.cond_br_with_expect(discr_value, llotherwise, lltarget, expect);
|
||||
}
|
||||
1 => {
|
||||
bx.cond_br_with_expect(discr_value, lltarget, llotherwise, expect);
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
} else {
|
||||
let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
|
||||
let llval = bx.const_uint_big(switch_llty, test_value);
|
||||
let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
|
||||
bx.cond_br(cmp, lltrue, llfalse);
|
||||
bx.cond_br_with_expect(cmp, lltarget, llotherwise, expect);
|
||||
}
|
||||
} else if self.cx.sess().opts.optimize == OptLevel::No
|
||||
&& target_iter.len() == 2
|
||||
|
@ -498,6 +498,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
}
|
||||
|
||||
sym::cold_path => {
|
||||
// This is a no-op. The intrinsic is just a hint to the optimizer.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
_ => {
|
||||
// Need to use backend-specific things in the implementation.
|
||||
return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
|
||||
|
@ -91,6 +91,10 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||
/// Cached terminate upon unwinding block and its reason
|
||||
terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>,
|
||||
|
||||
/// A bool flag for each basic block indicating whether it is a cold block.
|
||||
/// A cold block is a block that is unlikely to be executed at runtime.
|
||||
cold_blocks: IndexVec<mir::BasicBlock, bool>,
|
||||
|
||||
/// The location where each MIR arg/var/tmp/ret is stored. This is
|
||||
/// usually an `PlaceRef` representing an alloca, but not always:
|
||||
/// sometimes we can skip the alloca and just store the value
|
||||
@ -207,6 +211,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
cleanup_kinds,
|
||||
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
||||
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
||||
cold_blocks: find_cold_blocks(cx.tcx(), mir),
|
||||
locals: locals::Locals::empty(),
|
||||
debug_context,
|
||||
per_local_var_debug_info: None,
|
||||
@ -477,3 +482,39 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
fn find_cold_blocks<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir: &mir::Body<'tcx>,
|
||||
) -> IndexVec<mir::BasicBlock, bool> {
|
||||
let local_decls = &mir.local_decls;
|
||||
|
||||
let mut cold_blocks: IndexVec<mir::BasicBlock, bool> =
|
||||
IndexVec::from_elem(false, &mir.basic_blocks);
|
||||
|
||||
// Traverse all basic blocks from end of the function to the start.
|
||||
for (bb, bb_data) in traversal::postorder(mir) {
|
||||
let terminator = bb_data.terminator();
|
||||
|
||||
// If a BB ends with a call to a cold function, mark it as cold.
|
||||
if let mir::TerminatorKind::Call { ref func, .. } = terminator.kind
|
||||
&& let ty::FnDef(def_id, ..) = *func.ty(local_decls, tcx).kind()
|
||||
&& let attrs = tcx.codegen_fn_attrs(def_id)
|
||||
&& attrs.flags.contains(CodegenFnAttrFlags::COLD)
|
||||
{
|
||||
cold_blocks[bb] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If all successors of a BB are cold and there's at least one of them, mark this BB as cold
|
||||
let mut succ = terminator.successors();
|
||||
if let Some(first) = succ.next()
|
||||
&& cold_blocks[first]
|
||||
&& succ.all(|s| cold_blocks[s])
|
||||
{
|
||||
cold_blocks[bb] = true;
|
||||
}
|
||||
}
|
||||
|
||||
cold_blocks
|
||||
}
|
||||
|
@ -84,6 +84,26 @@ pub trait BuilderMethods<'a, 'tcx>:
|
||||
then_llbb: Self::BasicBlock,
|
||||
else_llbb: Self::BasicBlock,
|
||||
);
|
||||
|
||||
// Conditional with expectation.
|
||||
//
|
||||
// This function is opt-in for back ends.
|
||||
//
|
||||
// The default implementation calls `self.expect()` before emiting the branch
|
||||
// by calling `self.cond_br()`
|
||||
fn cond_br_with_expect(
|
||||
&mut self,
|
||||
mut cond: Self::Value,
|
||||
then_llbb: Self::BasicBlock,
|
||||
else_llbb: Self::BasicBlock,
|
||||
expect: Option<bool>,
|
||||
) {
|
||||
if let Some(expect) = expect {
|
||||
cond = self.expect(cond, expect);
|
||||
}
|
||||
self.cond_br(cond, then_llbb, else_llbb)
|
||||
}
|
||||
|
||||
fn switch(
|
||||
&mut self,
|
||||
v: Self::Value,
|
||||
|
@ -152,13 +152,20 @@ where
|
||||
let span = span.substitute_dummy(our_span);
|
||||
let err = mk(span, frames);
|
||||
let mut err = tcx.dcx().create_err(err);
|
||||
let can_be_spurious = matches!(error, InterpErrorKind::ResourceExhaustion(_));
|
||||
|
||||
let msg = error.diagnostic_message();
|
||||
error.add_args(&mut err);
|
||||
|
||||
// Use *our* span to label the interp error
|
||||
err.span_label(our_span, msg);
|
||||
ErrorHandled::Reported(err.emit().into(), span)
|
||||
let g = err.emit();
|
||||
let reported = if can_be_spurious {
|
||||
ReportedErrorInfo::spurious(g)
|
||||
} else {
|
||||
ReportedErrorInfo::from(g)
|
||||
};
|
||||
ErrorHandled::Reported(reported, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,6 +263,12 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
||||
}
|
||||
|
||||
/// See documentation on the `ptr_guaranteed_cmp` intrinsic.
|
||||
/// Returns `2` if the result is unknown.
|
||||
/// Returns `1` if the pointers are guaranteed equal.
|
||||
/// Returns `0` if the pointers are guaranteed inequal.
|
||||
///
|
||||
/// Note that this intrinsic is exposed on stable for comparison with null. In other words, any
|
||||
/// change to this function that affects comparison with null is insta-stable!
|
||||
fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
|
||||
interp_ok(match (a, b) {
|
||||
// Comparisons between integers are always known.
|
||||
|
@ -596,6 +596,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
// const-eval will return "tainted" errors if e.g. the layout cannot
|
||||
// be computed as the type references non-existing names.
|
||||
// See <https://github.com/rust-lang/rust/issues/124348>.
|
||||
} else if reported.can_be_spurious() {
|
||||
// These errors can just sometimes happen, even when the expression
|
||||
// is nominally "infallible", e.g. when running out of memory.
|
||||
} else {
|
||||
// Looks like the const is not captured by `required_consts`, that's bad.
|
||||
span_bug!(span, "interpret const eval failure of {val:?} which is not in required_consts");
|
||||
|
@ -417,6 +417,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
// These just return their argument
|
||||
self.copy_op(&args[0], dest)?;
|
||||
}
|
||||
sym::cold_path => {
|
||||
// This is a no-op. The intrinsic is just a hint to the optimizer.
|
||||
}
|
||||
sym::raw_eq => {
|
||||
let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
|
||||
self.write_scalar(result, dest)?;
|
||||
|
@ -1303,7 +1303,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
|
||||
fragment.make_trait_items()
|
||||
}
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_item(visitor, self.wrapped)
|
||||
walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
||||
@ -1344,7 +1344,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
|
||||
fragment.make_impl_items()
|
||||
}
|
||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||
walk_flat_map_item(visitor, self.wrapped)
|
||||
walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl)
|
||||
}
|
||||
fn is_mac_call(&self) -> bool {
|
||||
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
||||
|
@ -286,7 +286,7 @@ impl MutVisitor for PlaceholderExpander {
|
||||
AssocCtxt::Impl => it.make_impl_items(),
|
||||
}
|
||||
}
|
||||
_ => walk_flat_map_item(self, item),
|
||||
_ => walk_flat_map_assoc_item(self, item, ctxt),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,9 +109,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
|
||||
| sym::three_way_compare
|
||||
| sym::discriminant_value
|
||||
| sym::type_id
|
||||
| sym::likely
|
||||
| sym::unlikely
|
||||
| sym::select_unpredictable
|
||||
| sym::cold_path
|
||||
| sym::ptr_guaranteed_cmp
|
||||
| sym::minnumf16
|
||||
| sym::minnumf32
|
||||
@ -489,9 +488,8 @@ pub fn check_intrinsic_type(
|
||||
sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)),
|
||||
|
||||
sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit),
|
||||
sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
|
||||
sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
|
||||
sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)),
|
||||
sym::cold_path => (0, 0, vec![], tcx.types.unit),
|
||||
|
||||
sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
|
||||
sym::write_via_move => {
|
||||
|
@ -177,6 +177,7 @@ enum Scope<'a> {
|
||||
LateBoundary {
|
||||
s: ScopeRef<'a>,
|
||||
what: &'static str,
|
||||
deny_late_regions: bool,
|
||||
},
|
||||
|
||||
Root {
|
||||
@ -234,9 +235,11 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
||||
Scope::LateBoundary { s: _, what } => {
|
||||
f.debug_struct("LateBoundary").field("what", what).finish()
|
||||
}
|
||||
Scope::LateBoundary { s: _, what, deny_late_regions } => f
|
||||
.debug_struct("LateBoundary")
|
||||
.field("what", what)
|
||||
.field("deny_late_regions", deny_late_regions)
|
||||
.finish(),
|
||||
Scope::Root { opt_parent_item } => {
|
||||
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
||||
}
|
||||
@ -573,17 +576,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
// give, we will reverse the IndexMap after early captures.
|
||||
let mut late_depth = 0;
|
||||
let mut scope = self.scope;
|
||||
let mut crossed_late_boundary = None;
|
||||
let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)];
|
||||
loop {
|
||||
match *scope {
|
||||
Scope::Binder { ref bound_vars, scope_type, s, .. } => {
|
||||
for (&original_lifetime, &def) in bound_vars.iter().rev() {
|
||||
if let ResolvedArg::LateBound(..) = def
|
||||
&& crossed_late_boundary.is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) {
|
||||
let def = def.shifted(late_depth);
|
||||
let ident = lifetime_ident(original_lifetime);
|
||||
@ -624,12 +621,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
|
||||
Scope::ObjectLifetimeDefault { s, .. }
|
||||
| Scope::Supertrait { s, .. }
|
||||
| Scope::TraitRefBoundary { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
|
||||
Scope::LateBoundary { s, what, .. } => {
|
||||
crossed_late_boundary = Some(what);
|
||||
| Scope::TraitRefBoundary { s, .. }
|
||||
| Scope::LateBoundary { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
@ -640,7 +633,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope };
|
||||
self.with(scope, |this| {
|
||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||
this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
|
||||
this.with(scope, |this| {
|
||||
let scope = Scope::LateBoundary {
|
||||
s: this.scope,
|
||||
what: "nested `impl Trait`",
|
||||
// We can capture late-bound regions; we just don't duplicate
|
||||
// lifetime or const params, so we can't allow those.
|
||||
deny_late_regions: false,
|
||||
};
|
||||
this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
|
||||
})
|
||||
});
|
||||
|
||||
let captures = captures.into_inner().into_iter().collect();
|
||||
@ -997,9 +999,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
|
||||
self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
|
||||
intravisit::walk_anon_const(this, c);
|
||||
});
|
||||
self.with(
|
||||
Scope::LateBoundary { s: self.scope, what: "constant", deny_late_regions: true },
|
||||
|this| {
|
||||
intravisit::walk_anon_const(this, c);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
|
||||
@ -1291,8 +1296,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
scope = s;
|
||||
}
|
||||
|
||||
Scope::LateBoundary { s, what } => {
|
||||
crossed_late_boundary = Some(what);
|
||||
Scope::LateBoundary { s, what, deny_late_regions } => {
|
||||
if deny_late_regions {
|
||||
crossed_late_boundary = Some(what);
|
||||
}
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
@ -1508,7 +1515,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
scope = s;
|
||||
}
|
||||
|
||||
Scope::LateBoundary { s, what } => {
|
||||
Scope::LateBoundary { s, what, deny_late_regions: _ } => {
|
||||
crossed_late_boundary = Some(what);
|
||||
scope = s;
|
||||
}
|
||||
|
@ -68,6 +68,10 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
||||
}
|
||||
|
||||
impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> {
|
||||
fn visit_coroutine_kind(&mut self, coroutine_kind: &'a ast::CoroutineKind) -> Self::Result {
|
||||
self.check_id(coroutine_kind.closure_id());
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'a ast::Param) {
|
||||
self.with_lint_attrs(param.id, ¶m.attrs, |cx| {
|
||||
lint_callback!(cx, check_param, param);
|
||||
@ -111,17 +115,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
self.with_lint_attrs(e.id, &e.attrs, |cx| {
|
||||
lint_callback!(cx, check_expr, e);
|
||||
ast_visit::walk_expr(cx, e);
|
||||
// Explicitly check for lints associated with 'closure_id', since
|
||||
// it does not have a corresponding AST node
|
||||
match e.kind {
|
||||
ast::ExprKind::Closure(box ast::Closure {
|
||||
coroutine_kind: Some(coroutine_kind),
|
||||
..
|
||||
}) => {
|
||||
cx.check_id(coroutine_kind.closure_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
lint_callback!(cx, check_expr_post, e);
|
||||
})
|
||||
}
|
||||
@ -156,14 +149,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
lint_callback!(self, check_fn, fk, span, id);
|
||||
self.check_id(id);
|
||||
ast_visit::walk_fn(self, fk);
|
||||
|
||||
// Explicitly check for lints associated with 'closure_id', since
|
||||
// it does not have a corresponding AST node
|
||||
if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
self.check_id(coroutine_kind.closure_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_variant_data(&mut self, s: &'a ast::VariantData) {
|
||||
|
@ -584,6 +584,7 @@ enum UnusedDelimsCtx {
|
||||
MatchScrutineeExpr,
|
||||
ReturnValue,
|
||||
BlockRetValue,
|
||||
BreakValue,
|
||||
LetScrutineeExpr,
|
||||
ArrayLenExpr,
|
||||
AnonConst,
|
||||
@ -605,6 +606,7 @@ impl From<UnusedDelimsCtx> for &'static str {
|
||||
UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression",
|
||||
UnusedDelimsCtx::ReturnValue => "`return` value",
|
||||
UnusedDelimsCtx::BlockRetValue => "block return value",
|
||||
UnusedDelimsCtx::BreakValue => "`break` value",
|
||||
UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
|
||||
UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
|
||||
UnusedDelimsCtx::MatchArmExpr => "match arm expression",
|
||||
@ -913,6 +915,10 @@ trait UnusedDelimLint {
|
||||
(value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
|
||||
}
|
||||
|
||||
Break(_, Some(ref value)) => {
|
||||
(value, UnusedDelimsCtx::BreakValue, false, None, None, true)
|
||||
}
|
||||
|
||||
Index(_, ref value, _) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false),
|
||||
|
||||
Assign(_, ref value, _) | AssignOp(.., ref value) => {
|
||||
@ -1063,6 +1069,9 @@ impl UnusedDelimLint for UnusedParens {
|
||||
_,
|
||||
_,
|
||||
) if node.is_lazy()))
|
||||
&& !((ctx == UnusedDelimsCtx::ReturnValue
|
||||
|| ctx == UnusedDelimsCtx::BreakValue)
|
||||
&& matches!(inner.kind, ast::ExprKind::Assign(_, _, _)))
|
||||
{
|
||||
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
|
||||
}
|
||||
|
@ -4185,7 +4185,7 @@ declare_lint! {
|
||||
Warn,
|
||||
"never type fallback affecting unsafe function calls",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
|
||||
reason: FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(Edition::Edition2024),
|
||||
reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
|
||||
};
|
||||
@edition Edition2024 => Deny;
|
||||
@ -4239,7 +4239,7 @@ declare_lint! {
|
||||
Warn,
|
||||
"never type fallback affecting unsafe function calls",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||
reason: FutureIncompatibilityReason::EditionAndFutureReleaseError(Edition::Edition2024),
|
||||
reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
|
||||
};
|
||||
report_in_external_macro
|
||||
|
@ -381,6 +381,8 @@ pub enum FutureIncompatibilityReason {
|
||||
/// hard errors (and the lint removed). Preferably when there is some
|
||||
/// confidence that the number of impacted projects is very small (few
|
||||
/// should have a broken dependency in their dependency tree).
|
||||
///
|
||||
/// [`EditionAndFutureReleaseError`]: FutureIncompatibilityReason::EditionAndFutureReleaseError
|
||||
FutureReleaseErrorReportInDeps,
|
||||
/// Code that changes meaning in some way in a
|
||||
/// future release.
|
||||
@ -419,6 +421,28 @@ pub enum FutureIncompatibilityReason {
|
||||
/// slightly changes the text of the diagnostic, but is otherwise the
|
||||
/// same.
|
||||
EditionSemanticsChange(Edition),
|
||||
/// This will be an error in the provided edition *and* in a future
|
||||
/// release.
|
||||
///
|
||||
/// This variant a combination of [`FutureReleaseErrorDontReportInDeps`]
|
||||
/// and [`EditionError`]. This is useful in rare cases when we
|
||||
/// want to have "preview" of a breaking change in an edition, but do a
|
||||
/// breaking change later on all editions anyway.
|
||||
///
|
||||
/// [`EditionError`]: FutureIncompatibilityReason::EditionError
|
||||
/// [`FutureReleaseErrorDontReportInDeps`]: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
|
||||
EditionAndFutureReleaseError(Edition),
|
||||
/// This will change meaning in the provided edition *and* in a future
|
||||
/// release.
|
||||
///
|
||||
/// This variant a combination of [`FutureReleaseSemanticsChange`]
|
||||
/// and [`EditionSemanticsChange`]. This is useful in rare cases when we
|
||||
/// want to have "preview" of a breaking change in an edition, but do a
|
||||
/// breaking change later on all editions anyway.
|
||||
///
|
||||
/// [`EditionSemanticsChange`]: FutureIncompatibilityReason::EditionSemanticsChange
|
||||
/// [`FutureReleaseSemanticsChange`]: FutureIncompatibilityReason::FutureReleaseSemanticsChange
|
||||
EditionAndFutureReleaseSemanticsChange(Edition),
|
||||
/// A custom reason.
|
||||
///
|
||||
/// Choose this variant if the built-in text of the diagnostic of the
|
||||
@ -431,9 +455,15 @@ pub enum FutureIncompatibilityReason {
|
||||
impl FutureIncompatibilityReason {
|
||||
pub fn edition(self) -> Option<Edition> {
|
||||
match self {
|
||||
Self::EditionError(e) => Some(e),
|
||||
Self::EditionSemanticsChange(e) => Some(e),
|
||||
_ => None,
|
||||
Self::EditionError(e)
|
||||
| Self::EditionSemanticsChange(e)
|
||||
| Self::EditionAndFutureReleaseError(e)
|
||||
| Self::EditionAndFutureReleaseSemanticsChange(e) => Some(e),
|
||||
|
||||
FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
|
||||
| FutureIncompatibilityReason::FutureReleaseErrorReportInDeps
|
||||
| FutureIncompatibilityReason::FutureReleaseSemanticsChange
|
||||
| FutureIncompatibilityReason::Custom(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +382,17 @@ pub fn lint_level(
|
||||
FutureIncompatibilityReason::EditionSemanticsChange(edition) => {
|
||||
format!("this changes meaning in Rust {edition}")
|
||||
}
|
||||
FutureIncompatibilityReason::EditionAndFutureReleaseError(edition) => {
|
||||
format!(
|
||||
"this was previously accepted by the compiler but is being phased out; \
|
||||
it will become a hard error in Rust {edition} and in a future release in all editions!"
|
||||
)
|
||||
}
|
||||
FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(edition) => {
|
||||
format!(
|
||||
"this changes meaning in Rust {edition} and in a future release in all editions!"
|
||||
)
|
||||
}
|
||||
FutureIncompatibilityReason::Custom(reason) => reason.to_owned(),
|
||||
};
|
||||
|
||||
|
@ -59,22 +59,33 @@ impl ErrorHandled {
|
||||
pub struct ReportedErrorInfo {
|
||||
error: ErrorGuaranteed,
|
||||
is_tainted_by_errors: bool,
|
||||
/// Whether this is the kind of error that can sometimes occur, and sometimes not.
|
||||
/// Used for resource exhaustion errors.
|
||||
can_be_spurious: bool,
|
||||
}
|
||||
|
||||
impl ReportedErrorInfo {
|
||||
#[inline]
|
||||
pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
|
||||
ReportedErrorInfo { is_tainted_by_errors: true, error }
|
||||
ReportedErrorInfo { is_tainted_by_errors: true, can_be_spurious: false, error }
|
||||
}
|
||||
#[inline]
|
||||
pub fn spurious(error: ErrorGuaranteed) -> ReportedErrorInfo {
|
||||
ReportedErrorInfo { can_be_spurious: true, is_tainted_by_errors: false, error }
|
||||
}
|
||||
|
||||
pub fn is_tainted_by_errors(&self) -> bool {
|
||||
self.is_tainted_by_errors
|
||||
}
|
||||
pub fn can_be_spurious(&self) -> bool {
|
||||
self.can_be_spurious
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorGuaranteed> for ReportedErrorInfo {
|
||||
#[inline]
|
||||
fn from(error: ErrorGuaranteed) -> ReportedErrorInfo {
|
||||
ReportedErrorInfo { is_tainted_by_errors: false, error }
|
||||
ReportedErrorInfo { is_tainted_by_errors: false, can_be_spurious: false, error }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ pub enum InstantiationMode {
|
||||
LocalCopy,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum MonoItem<'tcx> {
|
||||
Fn(Instance<'tcx>),
|
||||
Static(DefId),
|
||||
@ -66,20 +66,7 @@ impl<'tcx> MonoItem<'tcx> {
|
||||
// change NON_INCR_MIN_CGU_SIZE as well.
|
||||
pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
|
||||
match *self {
|
||||
MonoItem::Fn(instance) => {
|
||||
match instance.def {
|
||||
// "Normal" functions size estimate: the number of
|
||||
// statements, plus one for the terminator.
|
||||
InstanceKind::Item(..)
|
||||
| InstanceKind::DropGlue(..)
|
||||
| InstanceKind::AsyncDropGlueCtorShim(..) => {
|
||||
let mir = tcx.instance_mir(instance.def);
|
||||
mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
|
||||
}
|
||||
// Other compiler-generated shims size estimate: 1
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
MonoItem::Fn(instance) => tcx.size_estimate(instance),
|
||||
// Conservatively estimate the size of a static declaration or
|
||||
// assembly item to be 1.
|
||||
MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1,
|
||||
@ -556,3 +543,21 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> {
|
||||
Symbol::intern(&cgu_name)
|
||||
}
|
||||
}
|
||||
|
||||
/// See module-level docs of `rustc_monomorphize::collector` on some context for "mentioned" items.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum CollectionMode {
|
||||
/// Collect items that are used, i.e., actually needed for codegen.
|
||||
///
|
||||
/// Which items are used can depend on optimization levels, as MIR optimizations can remove
|
||||
/// uses.
|
||||
UsedItems,
|
||||
/// Collect items that are mentioned. The goal of this mode is that it is independent of
|
||||
/// optimizations: the set of "mentioned" items is computed before optimizations are run.
|
||||
///
|
||||
/// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently
|
||||
/// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we
|
||||
/// might decide to run them before computing mentioned items.) The key property of this set is
|
||||
/// that it is optimization-independent.
|
||||
MentionedItems,
|
||||
}
|
||||
|
@ -216,6 +216,10 @@ impl<T0, T1> EraseType for (&'_ T0, &'_ [T1]) {
|
||||
type Result = [u8; size_of::<(&'static (), &'static [()])>()];
|
||||
}
|
||||
|
||||
impl<T0, T1> EraseType for (&'_ [T0], &'_ [T1]) {
|
||||
type Result = [u8; size_of::<(&'static [()], &'static [()])>()];
|
||||
}
|
||||
|
||||
impl<T0> EraseType for (&'_ T0, Result<(), ErrorGuaranteed>) {
|
||||
type Result = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()];
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
||||
use crate::infer::canonical::CanonicalQueryInput;
|
||||
use crate::mir::mono::CollectionMode;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::{TyAndLayout, ValidityRequirement};
|
||||
use crate::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt};
|
||||
@ -590,3 +591,11 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::Instance<'tcx>, CollectionMode) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ use rustc_session::cstore::{
|
||||
};
|
||||
use rustc_session::lint::LintExpectationId;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
@ -59,7 +60,7 @@ use crate::mir::interpret::{
|
||||
EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
|
||||
EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput,
|
||||
};
|
||||
use crate::mir::mono::CodegenUnit;
|
||||
use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem};
|
||||
use crate::query::erase::{Erase, erase, restore};
|
||||
use crate::query::plumbing::{
|
||||
CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at,
|
||||
@ -2339,6 +2340,16 @@ rustc_queries! {
|
||||
arena_cache
|
||||
desc { "functions to skip for move-size check" }
|
||||
}
|
||||
|
||||
query items_of_instance(key: (ty::Instance<'tcx>, CollectionMode)) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) {
|
||||
desc { "collecting items used by `{}`", key.0 }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
query size_estimate(key: ty::Instance<'tcx>) -> usize {
|
||||
desc { "estimating codegen size of `{}`", key }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
}
|
||||
|
||||
rustc_query_append! { define_callbacks! }
|
||||
|
@ -12,6 +12,7 @@ use rustc_index::{Idx, IndexVec};
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
|
||||
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::mir::{self, interpret};
|
||||
use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
@ -22,7 +23,7 @@ use rustc_session::Session;
|
||||
use rustc_span::hygiene::{
|
||||
ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
|
||||
};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::{
|
||||
BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span,
|
||||
SpanDecoder, SpanEncoder, StableSourceFileId, Symbol,
|
||||
@ -773,6 +774,13 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsm
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Spanned<MonoItem<'tcx>>] {
|
||||
#[inline]
|
||||
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
|
||||
RefDecodable::decode(d)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
|
||||
for &'tcx crate::traits::specialization_graph::Graph
|
||||
{
|
||||
|
@ -13,9 +13,11 @@ use std::marker::DiscriminantKind;
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::source_map::Spanned;
|
||||
pub use rustc_type_ir::{TyDecoder, TyEncoder};
|
||||
|
||||
use crate::arena::ArenaAllocatable;
|
||||
@ -397,6 +399,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [Spanned<MonoItem<'tcx>>] {
|
||||
fn decode(decoder: &mut D) -> &'tcx Self {
|
||||
decoder
|
||||
.interner()
|
||||
.arena
|
||||
.alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
|
||||
for ty::List<ty::BoundVariableKind>
|
||||
{
|
||||
|
@ -4,8 +4,8 @@ use rustc_middle::mir::{
|
||||
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
|
||||
};
|
||||
|
||||
use super::visitor::{ResultsVisitable, ResultsVisitor};
|
||||
use super::{Analysis, Effect, EffectIndex, SwitchIntTarget};
|
||||
use super::visitor::ResultsVisitor;
|
||||
use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
|
||||
|
||||
pub trait Direction {
|
||||
const IS_FORWARD: bool;
|
||||
@ -33,14 +33,14 @@ pub trait Direction {
|
||||
where
|
||||
A: Analysis<'tcx>;
|
||||
|
||||
fn visit_results_in_block<'mir, 'tcx, D, R>(
|
||||
state: &mut D,
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
results: &mut R,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
|
||||
results: &mut Results<'tcx, A>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||
) where
|
||||
R: ResultsVisitable<'tcx, Domain = D>;
|
||||
A: Analysis<'tcx>;
|
||||
|
||||
fn join_state_into_successors_of<'tcx, A>(
|
||||
analysis: &mut A,
|
||||
@ -53,7 +53,7 @@ pub trait Direction {
|
||||
A: Analysis<'tcx>;
|
||||
}
|
||||
|
||||
/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement).
|
||||
/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
|
||||
pub struct Backward;
|
||||
|
||||
impl Direction for Backward {
|
||||
@ -157,32 +157,32 @@ impl Direction for Backward {
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
}
|
||||
|
||||
fn visit_results_in_block<'mir, 'tcx, D, R>(
|
||||
state: &mut D,
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
results: &mut R,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
|
||||
results: &mut Results<'tcx, A>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||
) where
|
||||
R: ResultsVisitable<'tcx, Domain = D>,
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
results.reset_to_block_entry(state, block);
|
||||
state.clone_from(results.entry_set_for_block(block));
|
||||
|
||||
vis.visit_block_end(state);
|
||||
|
||||
// Terminator
|
||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||
let term = block_data.terminator();
|
||||
results.reconstruct_before_terminator_effect(state, term, loc);
|
||||
results.analysis.apply_before_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||
results.reconstruct_terminator_effect(state, term, loc);
|
||||
results.analysis.apply_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||
|
||||
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
|
||||
let loc = Location { block, statement_index };
|
||||
results.reconstruct_before_statement_effect(state, stmt, loc);
|
||||
results.analysis.apply_before_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||
results.reconstruct_statement_effect(state, stmt, loc);
|
||||
results.analysis.apply_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||
}
|
||||
|
||||
@ -389,32 +389,32 @@ impl Direction for Forward {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_results_in_block<'mir, 'tcx, F, R>(
|
||||
state: &mut F,
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
state: &mut A::Domain,
|
||||
block: BasicBlock,
|
||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||
results: &mut R,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>,
|
||||
results: &mut Results<'tcx, A>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||
) where
|
||||
R: ResultsVisitable<'tcx, Domain = F>,
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
results.reset_to_block_entry(state, block);
|
||||
state.clone_from(results.entry_set_for_block(block));
|
||||
|
||||
vis.visit_block_start(state);
|
||||
|
||||
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
|
||||
let loc = Location { block, statement_index };
|
||||
results.reconstruct_before_statement_effect(state, stmt, loc);
|
||||
results.analysis.apply_before_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||
results.reconstruct_statement_effect(state, stmt, loc);
|
||||
results.analysis.apply_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||
}
|
||||
|
||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||
let term = block_data.terminator();
|
||||
results.reconstruct_before_terminator_effect(state, term, loc);
|
||||
results.analysis.apply_before_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||
results.reconstruct_terminator_effect(state, term, loc);
|
||||
results.analysis.apply_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||
|
||||
vis.visit_block_end(state);
|
||||
|
@ -544,20 +544,18 @@ impl<D> StateDiffCollector<D> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
|
||||
impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector<A::Domain>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
A::Domain: DebugWithContext<A>,
|
||||
{
|
||||
type Domain = A::Domain;
|
||||
|
||||
fn visit_block_start(&mut self, state: &Self::Domain) {
|
||||
fn visit_block_start(&mut self, state: &A::Domain) {
|
||||
if A::Direction::IS_FORWARD {
|
||||
self.prev_state.clone_from(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_block_end(&mut self, state: &Self::Domain) {
|
||||
fn visit_block_end(&mut self, state: &A::Domain) {
|
||||
if A::Direction::IS_BACKWARD {
|
||||
self.prev_state.clone_from(state);
|
||||
}
|
||||
@ -566,7 +564,7 @@ where
|
||||
fn visit_statement_before_primary_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &Self::Domain,
|
||||
state: &A::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
@ -579,7 +577,7 @@ where
|
||||
fn visit_statement_after_primary_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &Self::Domain,
|
||||
state: &A::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
@ -590,7 +588,7 @@ where
|
||||
fn visit_terminator_before_primary_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &Self::Domain,
|
||||
state: &A::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
@ -603,7 +601,7 @@ where
|
||||
fn visit_terminator_after_primary_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &Self::Domain,
|
||||
state: &A::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
|
@ -55,8 +55,8 @@ mod visitor;
|
||||
pub use self::cursor::ResultsCursor;
|
||||
pub use self::direction::{Backward, Direction, Forward};
|
||||
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
|
||||
pub use self::results::Results;
|
||||
pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
|
||||
pub use self::results::{EntrySets, Results};
|
||||
pub use self::visitor::{ResultsVisitor, visit_results};
|
||||
|
||||
/// Analysis domains are all bitsets of various kinds. This trait holds
|
||||
/// operations needed by all of them.
|
||||
|
@ -18,7 +18,7 @@ use crate::errors::{
|
||||
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
|
||||
};
|
||||
|
||||
type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
|
||||
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
|
||||
|
||||
/// A dataflow analysis that has converged to fixpoint.
|
||||
#[derive(Clone)]
|
||||
@ -27,7 +27,7 @@ where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
pub analysis: A,
|
||||
pub(super) entry_sets: EntrySets<'tcx, A>,
|
||||
pub entry_sets: EntrySets<'tcx, A>,
|
||||
}
|
||||
|
||||
impl<'tcx, A> Results<'tcx, A>
|
||||
@ -51,7 +51,7 @@ where
|
||||
&mut self,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
blocks: impl IntoIterator<Item = BasicBlock>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||
) {
|
||||
visit_results(body, blocks, self, vis)
|
||||
}
|
||||
@ -59,7 +59,7 @@ where
|
||||
pub fn visit_reachable_with<'mir>(
|
||||
&mut self,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||
) {
|
||||
let blocks = traversal::reachable(body);
|
||||
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
|
||||
|
@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results};
|
||||
|
||||
/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
|
||||
/// dataflow state at that location.
|
||||
pub fn visit_results<'mir, 'tcx, D, R>(
|
||||
pub fn visit_results<'mir, 'tcx, A>(
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
blocks: impl IntoIterator<Item = BasicBlock>,
|
||||
results: &mut R,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
|
||||
results: &mut Results<'tcx, A>,
|
||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||
) where
|
||||
R: ResultsVisitable<'tcx, Domain = D>,
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
let mut state = results.bottom_value(body);
|
||||
let mut state = results.analysis.bottom_value(body);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
|
||||
@ -22,23 +22,23 @@ pub fn visit_results<'mir, 'tcx, D, R>(
|
||||
assert!(reachable_blocks.contains(block));
|
||||
|
||||
let block_data = &body[block];
|
||||
R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
|
||||
A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
|
||||
}
|
||||
}
|
||||
|
||||
/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
|
||||
/// visited.
|
||||
pub trait ResultsVisitor<'mir, 'tcx, R> {
|
||||
type Domain;
|
||||
|
||||
fn visit_block_start(&mut self, _state: &Self::Domain) {}
|
||||
/// A visitor over the results of an `Analysis`.
|
||||
pub trait ResultsVisitor<'mir, 'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
fn visit_block_start(&mut self, _state: &A::Domain) {}
|
||||
|
||||
/// Called with the `before_statement_effect` of the given statement applied to `state` but not
|
||||
/// its `statement_effect`.
|
||||
fn visit_statement_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
_state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
_statement: &'mir mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
@ -48,19 +48,19 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
|
||||
/// statement applied to `state`.
|
||||
fn visit_statement_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
_state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
_statement: &'mir mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but not
|
||||
/// its `terminator_effect`.
|
||||
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but
|
||||
/// not its `terminator_effect`.
|
||||
fn visit_terminator_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
_state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
_terminator: &'mir mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
@ -72,109 +72,12 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
|
||||
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
|
||||
fn visit_terminator_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
_state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
_terminator: &'mir mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
}
|
||||
|
||||
fn visit_block_end(&mut self, _state: &Self::Domain) {}
|
||||
}
|
||||
|
||||
/// Things that can be visited by a `ResultsVisitor`.
|
||||
///
|
||||
/// This trait exists so that we can visit the results of one or more dataflow analyses
|
||||
/// simultaneously.
|
||||
pub trait ResultsVisitable<'tcx> {
|
||||
type Direction: Direction;
|
||||
type Domain;
|
||||
|
||||
/// Creates an empty `Domain` to hold the transient state for these dataflow results.
|
||||
///
|
||||
/// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry`
|
||||
/// before it can be observed by a `ResultsVisitor`.
|
||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain;
|
||||
|
||||
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock);
|
||||
|
||||
fn reconstruct_before_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
);
|
||||
|
||||
fn reconstruct_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
);
|
||||
|
||||
fn reconstruct_before_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
);
|
||||
|
||||
fn reconstruct_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
);
|
||||
}
|
||||
|
||||
impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
|
||||
where
|
||||
A: Analysis<'tcx>,
|
||||
{
|
||||
type Domain = A::Domain;
|
||||
type Direction = A::Direction;
|
||||
|
||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
||||
self.analysis.bottom_value(body)
|
||||
}
|
||||
|
||||
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
|
||||
state.clone_from(self.entry_set_for_block(block));
|
||||
}
|
||||
|
||||
fn reconstruct_before_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.analysis.apply_before_statement_effect(state, stmt, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.analysis.apply_statement_effect(state, stmt, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_before_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.analysis.apply_before_terminator_effect(state, term, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.analysis.apply_terminator_effect(state, term, loc);
|
||||
}
|
||||
fn visit_block_end(&mut self, _state: &A::Domain) {}
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{
|
||||
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
|
||||
};
|
||||
pub use self::framework::{
|
||||
Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
|
||||
ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
|
||||
Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
|
||||
Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
|
||||
visit_results,
|
||||
};
|
||||
use self::move_paths::MoveData;
|
||||
|
@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::{self, BasicBlock, Body, Location};
|
||||
|
||||
use crate::framework::{ResultsVisitable, ResultsVisitor, visit_results};
|
||||
use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
|
||||
|
||||
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
||||
pub struct DenseLocationMap {
|
||||
@ -95,14 +95,14 @@ rustc_index::newtype_index! {
|
||||
}
|
||||
|
||||
/// Add points depending on the result of the given dataflow analysis.
|
||||
pub fn save_as_intervals<'tcx, N, R>(
|
||||
pub fn save_as_intervals<'tcx, N, A>(
|
||||
elements: &DenseLocationMap,
|
||||
body: &mir::Body<'tcx>,
|
||||
mut results: R,
|
||||
mut results: Results<'tcx, A>,
|
||||
) -> SparseIntervalMatrix<N, PointIndex>
|
||||
where
|
||||
N: Idx,
|
||||
R: ResultsVisitable<'tcx, Domain = BitSet<N>>,
|
||||
A: Analysis<'tcx, Domain = BitSet<N>>,
|
||||
{
|
||||
let values = SparseIntervalMatrix::new(elements.num_points());
|
||||
let mut visitor = Visitor { elements, values };
|
||||
@ -120,16 +120,15 @@ struct Visitor<'a, N: Idx> {
|
||||
values: SparseIntervalMatrix<N, PointIndex>,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
|
||||
impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N>
|
||||
where
|
||||
A: Analysis<'tcx, Domain = BitSet<N>>,
|
||||
N: Idx,
|
||||
{
|
||||
type Domain = BitSet<N>;
|
||||
|
||||
fn visit_statement_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
_statement: &'mir mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
@ -142,8 +141,8 @@ where
|
||||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
_terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
@ -68,11 +68,11 @@ use rustc_middle::ty::{
|
||||
self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::Analysis;
|
||||
use rustc_mir_dataflow::impls::{
|
||||
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
|
||||
};
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::symbol::sym;
|
||||
@ -817,9 +817,9 @@ impl ops::Deref for CoroutineSavedLocals {
|
||||
/// computation; see `CoroutineLayout` for more.
|
||||
fn compute_storage_conflicts<'mir, 'tcx>(
|
||||
body: &'mir Body<'tcx>,
|
||||
saved_locals: &CoroutineSavedLocals,
|
||||
saved_locals: &'mir CoroutineSavedLocals,
|
||||
always_live_locals: BitSet<Local>,
|
||||
mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
|
||||
mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
|
||||
) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
|
||||
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
|
||||
|
||||
@ -877,15 +877,13 @@ struct StorageConflictVisitor<'a, 'tcx> {
|
||||
eligible_storage_live: BitSet<Local>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
|
||||
for StorageConflictVisitor<'a, 'tcx>
|
||||
{
|
||||
type Domain = BitSet<Local>;
|
||||
|
||||
fn visit_statement_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
|
||||
state: &BitSet<Local>,
|
||||
_statement: &'a Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
@ -894,8 +892,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
||||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
state: &Self::Domain,
|
||||
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
|
||||
state: &BitSet<Local>,
|
||||
_terminator: &'a Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
|
@ -941,16 +941,12 @@ fn try_write_constant<'tcx>(
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>>
|
||||
for Collector<'_, 'tcx>
|
||||
{
|
||||
type Domain = State<FlatSet<Scalar>>;
|
||||
|
||||
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
|
||||
#[instrument(level = "trace", skip(self, results, statement))]
|
||||
fn visit_statement_before_primary_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||
state: &Self::Domain,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
statement: &'mir Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
@ -972,7 +968,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
|
||||
fn visit_statement_after_primary_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||
state: &Self::Domain,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
statement: &'mir Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
@ -997,7 +993,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
|
||||
fn visit_terminator_before_primary_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||
state: &Self::Domain,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
terminator: &'mir Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
@ -207,6 +207,7 @@
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_hir as hir;
|
||||
@ -215,7 +216,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
|
||||
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
|
||||
use rustc_middle::mir::mono::{CollectionMode, InstantiationMode, MonoItem};
|
||||
use rustc_middle::mir::visit::Visitor as MirVisitor;
|
||||
use rustc_middle::mir::{self, Location, MentionedItem, traversal};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
@ -243,16 +244,6 @@ pub(crate) enum MonoItemCollectionStrategy {
|
||||
Lazy,
|
||||
}
|
||||
|
||||
pub(crate) struct UsageMap<'tcx> {
|
||||
// Maps every mono item to the mono items used by it.
|
||||
used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
|
||||
|
||||
// Maps every mono item to the mono items that use it.
|
||||
user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
|
||||
}
|
||||
|
||||
type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>;
|
||||
|
||||
/// The state that is shared across the concurrent threads that are doing collection.
|
||||
struct SharedState<'tcx> {
|
||||
/// Items that have been or are currently being recursively collected.
|
||||
@ -264,22 +255,12 @@ struct SharedState<'tcx> {
|
||||
usage_map: MTLock<UsageMap<'tcx>>,
|
||||
}
|
||||
|
||||
/// See module-level docs on some contect for "mentioned" items.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum CollectionMode {
|
||||
/// Collect items that are used, i.e., actually needed for codegen.
|
||||
///
|
||||
/// Which items are used can depend on optimization levels, as MIR optimizations can remove
|
||||
/// uses.
|
||||
UsedItems,
|
||||
/// Collect items that are mentioned. The goal of this mode is that it is independent of
|
||||
/// optimizations: the set of "mentioned" items is computed before optimizations are run.
|
||||
///
|
||||
/// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently
|
||||
/// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we
|
||||
/// might decide to run them before computing mentioned items.) The key property of this set is
|
||||
/// that it is optimization-independent.
|
||||
MentionedItems,
|
||||
pub(crate) struct UsageMap<'tcx> {
|
||||
// Maps every mono item to the mono items used by it.
|
||||
used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
|
||||
|
||||
// Maps every mono item to the mono items that use it.
|
||||
user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> UsageMap<'tcx> {
|
||||
@ -287,19 +268,15 @@ impl<'tcx> UsageMap<'tcx> {
|
||||
UsageMap { used_map: Default::default(), user_map: Default::default() }
|
||||
}
|
||||
|
||||
fn record_used<'a>(
|
||||
&mut self,
|
||||
user_item: MonoItem<'tcx>,
|
||||
used_items: &'a [Spanned<MonoItem<'tcx>>],
|
||||
) where
|
||||
fn record_used<'a>(&mut self, user_item: MonoItem<'tcx>, used_items: &'a MonoItems<'tcx>)
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
let used_items: Vec<_> = used_items.iter().map(|item| item.node).collect();
|
||||
for &used_item in used_items.iter() {
|
||||
for used_item in used_items.items() {
|
||||
self.user_map.entry(used_item).or_default().push(user_item);
|
||||
}
|
||||
|
||||
assert!(self.used_map.insert(user_item, used_items).is_none());
|
||||
assert!(self.used_map.insert(user_item, used_items.items().collect()).is_none());
|
||||
}
|
||||
|
||||
pub(crate) fn get_user_items(&self, item: MonoItem<'tcx>) -> &[MonoItem<'tcx>] {
|
||||
@ -325,6 +302,52 @@ impl<'tcx> UsageMap<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct MonoItems<'tcx> {
|
||||
// We want a set of MonoItem + Span where trying to re-insert a MonoItem with a different Span
|
||||
// is ignored. Map does that, but it looks odd.
|
||||
items: FxIndexMap<MonoItem<'tcx>, Span>,
|
||||
}
|
||||
|
||||
impl<'tcx> MonoItems<'tcx> {
|
||||
fn new() -> Self {
|
||||
Self { items: FxIndexMap::default() }
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.items.is_empty()
|
||||
}
|
||||
|
||||
fn push(&mut self, item: Spanned<MonoItem<'tcx>>) {
|
||||
// Insert only if the entry does not exist. A normal insert would stomp the first span that
|
||||
// got inserted.
|
||||
self.items.entry(item.node).or_insert(item.span);
|
||||
}
|
||||
|
||||
fn items(&self) -> impl Iterator<Item = MonoItem<'tcx>> + '_ {
|
||||
self.items.keys().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> IntoIterator for MonoItems<'tcx> {
|
||||
type Item = Spanned<MonoItem<'tcx>>;
|
||||
type IntoIter = impl Iterator<Item = Spanned<MonoItem<'tcx>>>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.items.into_iter().map(|(item, span)| respan(span, item))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Extend<Spanned<MonoItem<'tcx>>> for MonoItems<'tcx> {
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
where
|
||||
I: IntoIterator<Item = Spanned<MonoItem<'tcx>>>,
|
||||
{
|
||||
for item in iter {
|
||||
self.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
|
||||
/// post-monomorphization error is encountered during a collection step.
|
||||
///
|
||||
@ -443,13 +466,9 @@ fn collect_items_rec<'tcx>(
|
||||
));
|
||||
|
||||
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
collect_items_of_instance(
|
||||
tcx,
|
||||
instance,
|
||||
&mut used_items,
|
||||
&mut mentioned_items,
|
||||
mode,
|
||||
)
|
||||
let (used, mentioned) = tcx.items_of_instance((instance, mode));
|
||||
used_items.extend(used.into_iter().copied());
|
||||
mentioned_items.extend(mentioned.into_iter().copied());
|
||||
});
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
@ -1171,14 +1190,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
|
||||
/// Scans the MIR in order to find function calls, closures, and drop-glue.
|
||||
///
|
||||
/// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
|
||||
#[instrument(skip(tcx, used_items, mentioned_items), level = "debug")]
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
fn collect_items_of_instance<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
used_items: &mut MonoItems<'tcx>,
|
||||
mentioned_items: &mut MonoItems<'tcx>,
|
||||
mode: CollectionMode,
|
||||
) {
|
||||
) -> (MonoItems<'tcx>, MonoItems<'tcx>) {
|
||||
// This item is getting monomorphized, do mono-time checks.
|
||||
tcx.ensure().check_mono_item(instance);
|
||||
|
||||
@ -1193,11 +1210,13 @@ fn collect_items_of_instance<'tcx>(
|
||||
// mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already
|
||||
// added to `used_items` in a hash set, which can efficiently query in the
|
||||
// `body.mentioned_items` loop below without even having to monomorphize the item.
|
||||
let mut used_items = MonoItems::new();
|
||||
let mut mentioned_items = MonoItems::new();
|
||||
let mut used_mentioned_items = Default::default();
|
||||
let mut collector = MirUsedCollector {
|
||||
tcx,
|
||||
body,
|
||||
used_items,
|
||||
used_items: &mut used_items,
|
||||
used_mentioned_items: &mut used_mentioned_items,
|
||||
instance,
|
||||
};
|
||||
@ -1212,7 +1231,7 @@ fn collect_items_of_instance<'tcx>(
|
||||
// them errors.
|
||||
for const_op in body.required_consts() {
|
||||
if let Some(val) = collector.eval_constant(const_op) {
|
||||
collect_const_value(tcx, val, mentioned_items);
|
||||
collect_const_value(tcx, val, &mut mentioned_items);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1221,9 +1240,23 @@ fn collect_items_of_instance<'tcx>(
|
||||
for item in body.mentioned_items() {
|
||||
if !collector.used_mentioned_items.contains(&item.node) {
|
||||
let item_mono = collector.monomorphize(item.node);
|
||||
visit_mentioned_item(tcx, &item_mono, item.span, mentioned_items);
|
||||
visit_mentioned_item(tcx, &item_mono, item.span, &mut mentioned_items);
|
||||
}
|
||||
}
|
||||
|
||||
(used_items, mentioned_items)
|
||||
}
|
||||
|
||||
fn items_of_instance<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
(instance, mode): (Instance<'tcx>, CollectionMode),
|
||||
) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) {
|
||||
let (used_items, mentioned_items) = collect_items_of_instance(tcx, instance, mode);
|
||||
|
||||
let used_items = tcx.arena.alloc_from_iter(used_items);
|
||||
let mentioned_items = tcx.arena.alloc_from_iter(mentioned_items);
|
||||
|
||||
(used_items, mentioned_items)
|
||||
}
|
||||
|
||||
/// `item` must be already monomorphized.
|
||||
@ -1304,7 +1337,7 @@ fn collect_const_value<'tcx>(
|
||||
#[instrument(skip(tcx, mode), level = "debug")]
|
||||
fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoItem<'_>> {
|
||||
debug!("collecting roots");
|
||||
let mut roots = Vec::new();
|
||||
let mut roots = MonoItems::new();
|
||||
|
||||
{
|
||||
let entry_fn = tcx.entry_fn(());
|
||||
@ -1596,4 +1629,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.hooks.should_codegen_locally = should_codegen_locally;
|
||||
providers.items_of_instance = items_of_instance;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#![feature(array_windows)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(let_chains)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
@ -36,9 +36,7 @@ fn do_check_abi<'tcx>(
|
||||
target_feature_def: DefId,
|
||||
mut emit_err: impl FnMut(Option<&'static str>),
|
||||
) {
|
||||
let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else {
|
||||
return;
|
||||
};
|
||||
let feature_def = tcx.sess.target.features_for_correct_vector_abi();
|
||||
let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def);
|
||||
for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
|
||||
let size = arg_abi.layout.size;
|
||||
|
@ -1319,5 +1319,20 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||
.unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
|
||||
};
|
||||
|
||||
providers.size_estimate = |tcx, instance| {
|
||||
match instance.def {
|
||||
// "Normal" functions size estimate: the number of
|
||||
// statements, plus one for the terminator.
|
||||
InstanceKind::Item(..)
|
||||
| InstanceKind::DropGlue(..)
|
||||
| InstanceKind::AsyncDropGlueCtorShim(..) => {
|
||||
let mir = tcx.instance_mir(instance.def);
|
||||
mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
|
||||
}
|
||||
// Other compiler-generated shims size estimate: 1
|
||||
_ => 1,
|
||||
}
|
||||
};
|
||||
|
||||
collector::provide(providers);
|
||||
}
|
||||
|
@ -650,8 +650,9 @@ pub(crate) struct LeftArrowOperator {
|
||||
#[diag(parse_remove_let)]
|
||||
pub(crate) struct RemoveLet {
|
||||
#[primary_span]
|
||||
#[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
|
||||
pub span: Span,
|
||||
#[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -2683,6 +2683,13 @@ impl<'a> Parser<'a> {
|
||||
// ^^
|
||||
// }
|
||||
//
|
||||
// We account for macro calls that were meant as conditions as well.
|
||||
//
|
||||
// if ... {
|
||||
// } else if macro! { foo bar } {
|
||||
// ^^
|
||||
// }
|
||||
//
|
||||
// If $cond is "statement-like" such as ExprKind::While then we
|
||||
// want to suggest wrapping in braces.
|
||||
//
|
||||
@ -2693,7 +2700,9 @@ impl<'a> Parser<'a> {
|
||||
// }
|
||||
// ^
|
||||
if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
|
||||
&& classify::expr_requires_semi_to_be_stmt(&cond) =>
|
||||
&& (classify::expr_requires_semi_to_be_stmt(&cond)
|
||||
|| matches!(cond.kind, ExprKind::MacCall(..)))
|
||||
=>
|
||||
{
|
||||
self.dcx().emit_err(errors::ExpectedElseBlock {
|
||||
first_tok_span,
|
||||
|
@ -685,7 +685,7 @@ impl<'a> Parser<'a> {
|
||||
self.bump();
|
||||
// Trim extra space after the `let`
|
||||
let span = lo.with_hi(self.token.span.lo());
|
||||
self.dcx().emit_err(RemoveLet { span });
|
||||
self.dcx().emit_err(RemoveLet { span: lo, suggestion: span });
|
||||
lo = self.token.span;
|
||||
}
|
||||
|
||||
|
@ -475,6 +475,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
|
||||
let prev = self.prev_token.span;
|
||||
let sp = self.token.span;
|
||||
let mut e = self.dcx().struct_span_err(sp, msg);
|
||||
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
|
||||
@ -514,14 +515,11 @@ impl<'a> Parser<'a> {
|
||||
} else {
|
||||
stmt.span
|
||||
};
|
||||
e.multipart_suggestion(
|
||||
"try placing this code inside a block",
|
||||
vec![
|
||||
(stmt_span.shrink_to_lo(), "{ ".to_string()),
|
||||
(stmt_span.shrink_to_hi(), " }".to_string()),
|
||||
],
|
||||
// Speculative; has been misleading in the past (#46836).
|
||||
Applicability::MaybeIncorrect,
|
||||
self.suggest_fixes_misparsed_for_loop_head(
|
||||
&mut e,
|
||||
prev.between(sp),
|
||||
stmt_span,
|
||||
&stmt.kind,
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
@ -534,6 +532,103 @@ impl<'a> Parser<'a> {
|
||||
e
|
||||
}
|
||||
|
||||
fn suggest_fixes_misparsed_for_loop_head(
|
||||
&self,
|
||||
e: &mut Diag<'_>,
|
||||
between: Span,
|
||||
stmt_span: Span,
|
||||
stmt_kind: &StmtKind,
|
||||
) {
|
||||
match (&self.token.kind, &stmt_kind) {
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
if let ExprKind::Call(..) = expr.kind =>
|
||||
{
|
||||
// for _ in x y() {}
|
||||
e.span_suggestion_verbose(
|
||||
between,
|
||||
"you might have meant to write a method call",
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
if let ExprKind::Field(..) = expr.kind =>
|
||||
{
|
||||
// for _ in x y.z {}
|
||||
e.span_suggestion_verbose(
|
||||
between,
|
||||
"you might have meant to write a field access",
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
if let ExprKind::Struct(expr) = &expr.kind
|
||||
&& let None = expr.qself
|
||||
&& expr.path.segments.len() == 1 =>
|
||||
{
|
||||
// This is specific to "mistyped `if` condition followed by empty body"
|
||||
//
|
||||
// for _ in x y {}
|
||||
e.span_suggestion_verbose(
|
||||
between,
|
||||
"you might have meant to write a field access",
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
if let ExprKind::Lit(lit) = expr.kind
|
||||
&& let None = lit.suffix
|
||||
&& let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
|
||||
{
|
||||
// for _ in x 0 {}
|
||||
// for _ in x 0.0 {}
|
||||
e.span_suggestion_verbose(
|
||||
between,
|
||||
format!("you might have meant to write a field access"),
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
if let ExprKind::Loop(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::TryBlock(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Closure(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Try(..) = expr.kind =>
|
||||
{
|
||||
// These are more likely to have been meant as a block body.
|
||||
e.multipart_suggestion(
|
||||
"you might have meant to write this as part of a block",
|
||||
vec![
|
||||
(stmt_span.shrink_to_lo(), "{ ".to_string()),
|
||||
(stmt_span.shrink_to_hi(), " }".to_string()),
|
||||
],
|
||||
// Speculative; has been misleading in the past (#46836).
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), _) => {}
|
||||
(_, _) => {
|
||||
e.multipart_suggestion(
|
||||
"you might have meant to write this as part of a block",
|
||||
vec![
|
||||
(stmt_span.shrink_to_lo(), "{ ".to_string()),
|
||||
(stmt_span.shrink_to_hi(), " }".to_string()),
|
||||
],
|
||||
// Speculative; has been misleading in the past (#46836).
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
|
||||
let tok = super::token_descr(&self.token);
|
||||
let msg = format!("expected `{{`, found {tok}");
|
||||
|
@ -1324,7 +1324,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
||||
// This way they can use `macro_rules` defined later.
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(&item.ident);
|
||||
item.kind.walk(item, AssocCtxt::Trait, self);
|
||||
item.kind.walk(item.span, item.id, &item.ident, &item.vis, (), self);
|
||||
visit::walk_list!(self, visit_attribute, &item.attrs);
|
||||
}
|
||||
_ => visit::walk_item(self, item),
|
||||
|
@ -589,6 +589,7 @@ symbols! {
|
||||
cmse_nonsecure_entry,
|
||||
coerce_unsized,
|
||||
cold,
|
||||
cold_path,
|
||||
collapse_debuginfo,
|
||||
column,
|
||||
compare_bytes,
|
||||
|
@ -598,7 +598,12 @@ const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
|
||||
const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[/*(64, "zvl64b"), */ (128, "v")];
|
||||
// Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
|
||||
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(128, "vis")*/];
|
||||
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
|
||||
|
||||
const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
|
||||
const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
|
||||
const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
|
||||
|
||||
impl super::spec::Target {
|
||||
pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
|
||||
@ -620,20 +625,24 @@ impl super::spec::Target {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns None if we do not support ABI checks on the given target yet.
|
||||
pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> {
|
||||
pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
|
||||
match &*self.arch {
|
||||
"x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
"aarch64" | "arm64ec" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
"arm" => Some(ARM_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
"powerpc" | "powerpc64" => Some(POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
"loongarch64" => Some(&[]), // on-stack ABI, so we complain about all by-val vectors
|
||||
"riscv32" | "riscv64" => Some(RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
"wasm32" | "wasm64" => Some(WASM_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
"s390x" => Some(S390X_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
"sparc" | "sparc64" => Some(SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI),
|
||||
// FIXME: add support for non-tier2 architectures
|
||||
_ => None,
|
||||
"x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"loongarch64" => &[], // on-stack ABI, so we complain about all by-val vectors
|
||||
"riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
"bpf" => &[], // no vector ABI
|
||||
"csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
|
||||
// FIXME: for some tier3 targets, we are overly cautious and always give warnings
|
||||
// when passing args in vector registers.
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ use crate::vec::Vec;
|
||||
/// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider
|
||||
/// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8
|
||||
/// is a variable width encoding, `String`s are typically smaller than an array of
|
||||
/// the same `chars`:
|
||||
/// the same `char`s:
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
|
@ -1465,6 +1465,22 @@ pub const unsafe fn assume(b: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Hints to the compiler that current code path is cold.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_nounwind]
|
||||
#[miri::intrinsic_fallback_is_spec]
|
||||
#[cold]
|
||||
pub const fn cold_path() {}
|
||||
|
||||
/// Hints to the compiler that branch condition is likely to be true.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
@ -1480,13 +1496,21 @@ pub const unsafe fn assume(b: bool) {
|
||||
bootstrap,
|
||||
rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
|
||||
)]
|
||||
#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
#[miri::intrinsic_fallback_is_spec]
|
||||
#[inline(always)]
|
||||
pub const fn likely(b: bool) -> bool {
|
||||
b
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
b
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
if b {
|
||||
true
|
||||
} else {
|
||||
cold_path();
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
@ -1504,13 +1528,21 @@ pub const fn likely(b: bool) -> bool {
|
||||
bootstrap,
|
||||
rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
|
||||
)]
|
||||
#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
#[miri::intrinsic_fallback_is_spec]
|
||||
#[inline(always)]
|
||||
pub const fn unlikely(b: bool) -> bool {
|
||||
b
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
b
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
if b {
|
||||
cold_path();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns either `true_val` or `false_val` depending on condition `b` with a
|
||||
@ -3292,8 +3324,8 @@ pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T)
|
||||
|
||||
/// See documentation of `<*const T>::guaranteed_eq` for details.
|
||||
/// Returns `2` if the result is unknown.
|
||||
/// Returns `1` if the pointers are guaranteed equal
|
||||
/// Returns `0` if the pointers are guaranteed inequal
|
||||
/// Returns `1` if the pointers are guaranteed equal.
|
||||
/// Returns `0` if the pointers are guaranteed inequal.
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
@ -3535,7 +3567,6 @@ pub(crate) macro const_eval_select {
|
||||
/// In other words, the following code has *Undefined Behavior*:
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(is_val_statically_known)]
|
||||
/// #![feature(core_intrinsics)]
|
||||
/// # #![allow(internal_features)]
|
||||
/// use std::hint::unreachable_unchecked;
|
||||
@ -3548,7 +3579,6 @@ pub(crate) macro const_eval_select {
|
||||
/// may panic, or it may not:
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(is_val_statically_known)]
|
||||
/// #![feature(core_intrinsics)]
|
||||
/// # #![allow(internal_features)]
|
||||
/// use std::intrinsics::is_val_statically_known;
|
||||
@ -3581,7 +3611,6 @@ pub(crate) macro const_eval_select {
|
||||
/// behave identically:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(is_val_statically_known)]
|
||||
/// #![feature(core_intrinsics)]
|
||||
/// # #![allow(internal_features)]
|
||||
/// use std::intrinsics::is_val_statically_known;
|
||||
@ -3598,7 +3627,11 @@ pub(crate) macro const_eval_select {
|
||||
/// # _ = foo(&5_i32);
|
||||
/// # _ = bar(&5_i32);
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
|
||||
#[cfg_attr(
|
||||
bootstrap,
|
||||
rustc_const_stable(feature = "const_is_val_statically_known", since = "CURRENT_RUSTC_VERSION")
|
||||
)]
|
||||
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
|
||||
#[rustc_nounwind]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
@ -4013,9 +4046,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
|
||||
count: usize = count,
|
||||
) => {
|
||||
let zero_size = count == 0 || size == 0;
|
||||
ub_checks::is_aligned_and_not_null(src, align, zero_size)
|
||||
&& ub_checks::is_aligned_and_not_null(dst, align, zero_size)
|
||||
&& ub_checks::is_nonoverlapping(src, dst, size, count)
|
||||
ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
|
||||
&& ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
|
||||
&& ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
|
||||
}
|
||||
);
|
||||
|
||||
@ -4119,8 +4152,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
||||
align: usize = align_of::<T>(),
|
||||
zero_size: bool = T::IS_ZST || count == 0,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(src, align, zero_size)
|
||||
&& ub_checks::is_aligned_and_not_null(dst, align, zero_size)
|
||||
ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
|
||||
&& ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
|
||||
);
|
||||
copy(src, dst, count)
|
||||
}
|
||||
@ -4201,7 +4234,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
|
||||
addr: *const () = dst as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
zero_size: bool = T::IS_ZST || count == 0,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, zero_size)
|
||||
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
|
||||
);
|
||||
write_bytes(dst, val, count)
|
||||
}
|
||||
|
@ -109,6 +109,7 @@
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(const_exact_div))]
|
||||
#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
|
||||
#![cfg_attr(bootstrap, feature(const_ub_checks))]
|
||||
#![feature(array_ptr_get)]
|
||||
#![feature(asm_experimental_arch)]
|
||||
#![feature(const_align_of_val)]
|
||||
@ -121,7 +122,6 @@
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_nonnull_new)]
|
||||
#![feature(const_pin_2)]
|
||||
#![feature(const_ptr_is_null)]
|
||||
#![feature(const_ptr_sub_ptr)]
|
||||
#![feature(const_raw_ptr_comparison)]
|
||||
#![feature(const_size_of_val)]
|
||||
@ -132,14 +132,12 @@
|
||||
#![feature(const_type_id)]
|
||||
#![feature(const_type_name)]
|
||||
#![feature(const_typed_swap)]
|
||||
#![feature(const_ub_checks)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(coverage_attribute)]
|
||||
#![feature(do_not_recommend)]
|
||||
#![feature(internal_impls_macro)]
|
||||
#![feature(ip)]
|
||||
#![feature(is_ascii_octdigit)]
|
||||
#![feature(is_val_statically_known)]
|
||||
#![feature(lazy_get)]
|
||||
#![feature(link_cfg)]
|
||||
#![feature(non_null_from_ref)]
|
||||
|
@ -2242,7 +2242,6 @@ macro_rules! int_impl {
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
||||
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||
if exp == 0 {
|
||||
return 1;
|
||||
@ -2808,7 +2807,6 @@ macro_rules! int_impl {
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
||||
pub const fn pow(self, mut exp: u32) -> Self {
|
||||
if exp == 0 {
|
||||
return 1;
|
||||
|
@ -2251,7 +2251,6 @@ macro_rules! uint_impl {
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
||||
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||
if exp == 0 {
|
||||
return 1;
|
||||
@ -2791,7 +2790,6 @@ macro_rules! uint_impl {
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
||||
pub const fn pow(self, mut exp: u32) -> Self {
|
||||
if exp == 0 {
|
||||
return 1;
|
||||
|
@ -29,16 +29,18 @@ impl<T: ?Sized> *const T {
|
||||
/// assert!(!ptr.is_null());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
||||
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_diagnostic_item = "ptr_const_is_null"]
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
pub const fn is_null(self) -> bool {
|
||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||
// considering their "data" part for null-ness.
|
||||
let ptr = self as *const u8;
|
||||
const_eval_select!(
|
||||
@capture { ptr: *const u8 } -> bool:
|
||||
if const #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] {
|
||||
// This use of `const_raw_ptr_comparison` has been explicitly blessed by t-lang.
|
||||
if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] {
|
||||
match (ptr).guaranteed_eq(null_mut()) {
|
||||
Some(res) => res,
|
||||
// To remain maximally convervative, we stop execution when we don't
|
||||
@ -280,7 +282,7 @@ impl<T: ?Sized> *const T {
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
||||
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[inline]
|
||||
pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
||||
// SAFETY: the caller must guarantee that `self` is valid
|
||||
|
@ -1103,9 +1103,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||
count: usize = count,
|
||||
) => {
|
||||
let zero_size = size == 0 || count == 0;
|
||||
ub_checks::is_aligned_and_not_null(x, align, zero_size)
|
||||
&& ub_checks::is_aligned_and_not_null(y, align, zero_size)
|
||||
&& ub_checks::is_nonoverlapping(x, y, size, count)
|
||||
ub_checks::maybe_is_aligned_and_not_null(x, align, zero_size)
|
||||
&& ub_checks::maybe_is_aligned_and_not_null(y, align, zero_size)
|
||||
&& ub_checks::maybe_is_nonoverlapping(x, y, size, count)
|
||||
}
|
||||
);
|
||||
|
||||
@ -1216,7 +1216,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
|
||||
addr: *const () = dst as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
mem::replace(&mut *dst, src)
|
||||
}
|
||||
@ -1369,7 +1369,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
|
||||
addr: *const () = src as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
crate::intrinsics::read_via_copy(src)
|
||||
}
|
||||
@ -1573,7 +1573,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
|
||||
addr: *mut () = dst as *mut (),
|
||||
align: usize = align_of::<T>(),
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
intrinsics::write_via_move(dst, src)
|
||||
}
|
||||
@ -1745,7 +1745,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||
addr: *const () = src as *const (),
|
||||
align: usize = align_of::<T>(),
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
intrinsics::volatile_load(src)
|
||||
}
|
||||
@ -1825,7 +1825,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
|
||||
addr: *mut () = dst as *mut (),
|
||||
align: usize = align_of::<T>(),
|
||||
is_zst: bool = T::IS_ZST,
|
||||
) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
|
||||
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
intrinsics::volatile_store(dst, src);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ impl<T: ?Sized> *mut T {
|
||||
/// assert!(!ptr.is_null());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
||||
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_diagnostic_item = "ptr_is_null"]
|
||||
#[inline]
|
||||
pub const fn is_null(self) -> bool {
|
||||
@ -271,7 +271,7 @@ impl<T: ?Sized> *mut T {
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
||||
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[inline]
|
||||
pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
||||
// SAFETY: the caller must guarantee that `self` is valid for a
|
||||
@ -619,7 +619,7 @@ impl<T: ?Sized> *mut T {
|
||||
/// println!("{s:?}"); // It'll print: "[4, 2, 3]".
|
||||
/// ```
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
||||
#[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[inline]
|
||||
pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
|
||||
// SAFETY: the caller must guarantee that `self` is be valid for
|
||||
|
@ -132,7 +132,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
|
||||
align: usize = align_of::<T>(),
|
||||
len: usize = len,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(data, align, false)
|
||||
ub_checks::maybe_is_aligned_and_not_null(data, align, false)
|
||||
&& ub_checks::is_valid_allocation_size(size, len)
|
||||
);
|
||||
&*ptr::slice_from_raw_parts(data, len)
|
||||
@ -186,7 +186,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
|
||||
align: usize = align_of::<T>(),
|
||||
len: usize = len,
|
||||
) =>
|
||||
ub_checks::is_aligned_and_not_null(data, align, false)
|
||||
ub_checks::maybe_is_aligned_and_not_null(data, align, false)
|
||||
&& ub_checks::is_valid_allocation_size(size, len)
|
||||
);
|
||||
&mut *ptr::slice_from_raw_parts_mut(data, len)
|
||||
|
@ -469,7 +469,7 @@ impl AtomicBool {
|
||||
/// [valid]: crate::ptr#safety
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
||||
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
||||
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
|
||||
// SAFETY: guaranteed by the caller
|
||||
unsafe { &*ptr.cast() }
|
||||
@ -1264,7 +1264,7 @@ impl<T> AtomicPtr<T> {
|
||||
/// [valid]: crate::ptr#safety
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
||||
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
||||
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
|
||||
// SAFETY: guaranteed by the caller
|
||||
unsafe { &*ptr.cast() }
|
||||
@ -2263,7 +2263,7 @@ macro_rules! atomic_int {
|
||||
/// [valid]: crate::ptr#safety
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
||||
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
||||
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
|
||||
// SAFETY: guaranteed by the caller
|
||||
unsafe { &*ptr.cast() }
|
||||
|
@ -64,8 +64,6 @@ macro_rules! assert_unsafe_precondition {
|
||||
#[rustc_no_mir_inline]
|
||||
#[inline]
|
||||
#[rustc_nounwind]
|
||||
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
|
||||
#[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks
|
||||
const fn precondition_check($($name:$ty),*) {
|
||||
if !$e {
|
||||
::core::panicking::panic_nounwind(
|
||||
@ -116,12 +114,16 @@ pub(crate) const fn check_language_ub() -> bool {
|
||||
/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
|
||||
/// check is anyway not executed in `const`.
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
||||
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
pub(crate) const fn maybe_is_aligned_and_not_null(
|
||||
ptr: *const (),
|
||||
align: usize,
|
||||
is_zst: bool,
|
||||
) -> bool {
|
||||
// This is just for safety checks so we can const_eval_select.
|
||||
const_eval_select!(
|
||||
@capture { ptr: *const (), align: usize, is_zst: bool } -> bool:
|
||||
if const #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] {
|
||||
if const {
|
||||
is_zst || !ptr.is_null()
|
||||
} else {
|
||||
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
|
||||
@ -141,8 +143,8 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
|
||||
/// Note that in const-eval this function just returns `true` and therefore must
|
||||
/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
||||
pub(crate) const fn is_nonoverlapping(
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
pub(crate) const fn maybe_is_nonoverlapping(
|
||||
src: *const (),
|
||||
dst: *const (),
|
||||
size: usize,
|
||||
|
@ -55,4 +55,4 @@ ENV RUST_CONFIGURE_ARGS \
|
||||
|
||||
ENV SCRIPT \
|
||||
python3 ../x.py --stage 2 build && \
|
||||
python3 ../x.py --stage 2 test tests/run-make --test-args clang
|
||||
python3 ../x.py --stage 2 test tests/run-make
|
||||
|
@ -692,8 +692,6 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
|
||||
const quadcolon = /::\s*::/.exec(path);
|
||||
if (path.startsWith("::")) {
|
||||
throw ["Paths cannot start with ", "::"];
|
||||
} else if (path.endsWith("::")) {
|
||||
throw ["Paths cannot end with ", "::"];
|
||||
} else if (quadcolon !== null) {
|
||||
throw ["Unexpected ", quadcolon[0]];
|
||||
}
|
||||
@ -3974,18 +3972,19 @@ class DocSearch {
|
||||
|
||||
if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
|
||||
const elem = parsedQuery.elems[0];
|
||||
for (const id of this.nameTrie.search(elem.normalizedPathLast, this.tailTable)) {
|
||||
// use arrow functions to preserve `this`.
|
||||
const handleNameSearch = id => {
|
||||
const row = this.searchIndex[id];
|
||||
if (!typePassesFilter(elem.typeFilter, row.ty) ||
|
||||
(filterCrates !== null && row.crate !== filterCrates)) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
let pathDist = 0;
|
||||
if (elem.fullPath.length > 1) {
|
||||
pathDist = checkPath(elem.pathWithoutLast, row);
|
||||
if (pathDist === null) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4008,9 +4007,20 @@ class DocSearch {
|
||||
maxEditDistance,
|
||||
);
|
||||
}
|
||||
};
|
||||
if (elem.normalizedPathLast !== "") {
|
||||
const last = elem.normalizedPathLast;
|
||||
for (const id of this.nameTrie.search(last, this.tailTable)) {
|
||||
handleNameSearch(id);
|
||||
}
|
||||
}
|
||||
const length = this.searchIndex.length;
|
||||
|
||||
for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) {
|
||||
// queries that end in :: bypass the trie
|
||||
if (elem.normalizedPathLast === "") {
|
||||
handleNameSearch(i);
|
||||
}
|
||||
const row = this.searchIndex[i];
|
||||
if (filterCrates !== null && row.crate !== filterCrates) {
|
||||
continue;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 4a2d8dc636445b276288543882e076f254b3ae95
|
||||
Subproject commit 69e595908e2c420e7f0d1be34e6c5b984c8cfb84
|
@ -1 +1 @@
|
||||
3bc6916f4ca50bb83b211d9013dac38e84618750
|
||||
3fb7e441aecc3c054d71eb4d752d06e7776e8888
|
||||
|
@ -1,2 +1,2 @@
|
||||
The loop took around 1250ms
|
||||
The loop took around 1350ms
|
||||
(It's fine for this number to change when you `--bless` this test.)
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::artifact_names::{dynamic_lib_name, static_lib_name};
|
||||
use crate::external_deps::cc::{cc, cxx};
|
||||
use crate::external_deps::c_cxx_compiler::{cc, cxx};
|
||||
use crate::external_deps::llvm::llvm_ar;
|
||||
use crate::path_helpers::path;
|
||||
use crate::targets::{is_darwin, is_msvc, is_windows};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::command::Command;
|
||||
use crate::{env_var, is_msvc, is_windows, uname};
|
||||
use crate::{env_var, is_msvc};
|
||||
|
||||
/// Construct a new platform-specific C compiler invocation.
|
||||
///
|
||||
@ -127,99 +127,3 @@ impl Cc {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// `EXTRACFLAGS`
|
||||
pub fn extra_c_flags() -> Vec<&'static str> {
|
||||
// Adapted from tools.mk (trimmed):
|
||||
//
|
||||
// ```makefile
|
||||
// ifdef IS_WINDOWS
|
||||
// ifdef IS_MSVC
|
||||
// EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib
|
||||
// else
|
||||
// EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization
|
||||
// endif
|
||||
// else
|
||||
// ifeq ($(UNAME),Darwin)
|
||||
// EXTRACFLAGS := -lresolv
|
||||
// else
|
||||
// ifeq ($(UNAME),FreeBSD)
|
||||
// EXTRACFLAGS := -lm -lpthread -lgcc_s
|
||||
// else
|
||||
// ifeq ($(UNAME),SunOS)
|
||||
// EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
|
||||
// else
|
||||
// ifeq ($(UNAME),OpenBSD)
|
||||
// EXTRACFLAGS := -lm -lpthread -lc++abi
|
||||
// else
|
||||
// EXTRACFLAGS := -lm -lrt -ldl -lpthread
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// ```
|
||||
|
||||
if is_windows() {
|
||||
if is_msvc() {
|
||||
vec![
|
||||
"ws2_32.lib",
|
||||
"userenv.lib",
|
||||
"advapi32.lib",
|
||||
"bcrypt.lib",
|
||||
"ntdll.lib",
|
||||
"synchronization.lib",
|
||||
]
|
||||
} else {
|
||||
vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
|
||||
}
|
||||
} else {
|
||||
match uname() {
|
||||
n if n.contains("Darwin") => vec!["-lresolv"],
|
||||
n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"],
|
||||
n if n.contains("SunOS") => {
|
||||
vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"]
|
||||
}
|
||||
n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"],
|
||||
_ => vec!["-lm", "-lrt", "-ldl", "-lpthread"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `EXTRACXXFLAGS`
|
||||
pub fn extra_cxx_flags() -> Vec<&'static str> {
|
||||
// Adapted from tools.mk (trimmed):
|
||||
//
|
||||
// ```makefile
|
||||
// ifdef IS_WINDOWS
|
||||
// ifdef IS_MSVC
|
||||
// else
|
||||
// EXTRACXXFLAGS := -lstdc++
|
||||
// endif
|
||||
// else
|
||||
// ifeq ($(UNAME),Darwin)
|
||||
// EXTRACXXFLAGS := -lc++
|
||||
// else
|
||||
// ifeq ($(UNAME),FreeBSD)
|
||||
// else
|
||||
// ifeq ($(UNAME),SunOS)
|
||||
// else
|
||||
// ifeq ($(UNAME),OpenBSD)
|
||||
// else
|
||||
// EXTRACXXFLAGS := -lstdc++
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// ```
|
||||
if is_windows() {
|
||||
if is_msvc() { vec![] } else { vec!["-lstdc++"] }
|
||||
} else {
|
||||
match &uname()[..] {
|
||||
"Darwin" => vec!["-lc++"],
|
||||
"FreeBSD" | "SunOS" | "OpenBSD" => vec![],
|
||||
_ => vec!["-lstdc++"],
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
use crate::{is_msvc, is_windows, uname};
|
||||
|
||||
/// `EXTRACFLAGS`
|
||||
pub fn extra_c_flags() -> Vec<&'static str> {
|
||||
// Adapted from tools.mk (trimmed):
|
||||
//
|
||||
// ```makefile
|
||||
// ifdef IS_WINDOWS
|
||||
// ifdef IS_MSVC
|
||||
// EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib
|
||||
// else
|
||||
// EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization
|
||||
// endif
|
||||
// else
|
||||
// ifeq ($(UNAME),Darwin)
|
||||
// EXTRACFLAGS := -lresolv
|
||||
// else
|
||||
// ifeq ($(UNAME),FreeBSD)
|
||||
// EXTRACFLAGS := -lm -lpthread -lgcc_s
|
||||
// else
|
||||
// ifeq ($(UNAME),SunOS)
|
||||
// EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
|
||||
// else
|
||||
// ifeq ($(UNAME),OpenBSD)
|
||||
// EXTRACFLAGS := -lm -lpthread -lc++abi
|
||||
// else
|
||||
// EXTRACFLAGS := -lm -lrt -ldl -lpthread
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// ```
|
||||
|
||||
if is_windows() {
|
||||
if is_msvc() {
|
||||
vec![
|
||||
"ws2_32.lib",
|
||||
"userenv.lib",
|
||||
"advapi32.lib",
|
||||
"bcrypt.lib",
|
||||
"ntdll.lib",
|
||||
"synchronization.lib",
|
||||
]
|
||||
} else {
|
||||
vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
|
||||
}
|
||||
} else {
|
||||
match uname() {
|
||||
n if n.contains("Darwin") => vec!["-lresolv"],
|
||||
n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"],
|
||||
n if n.contains("SunOS") => {
|
||||
vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"]
|
||||
}
|
||||
n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"],
|
||||
_ => vec!["-lm", "-lrt", "-ldl", "-lpthread"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `EXTRACXXFLAGS`
|
||||
pub fn extra_cxx_flags() -> Vec<&'static str> {
|
||||
// Adapted from tools.mk (trimmed):
|
||||
//
|
||||
// ```makefile
|
||||
// ifdef IS_WINDOWS
|
||||
// ifdef IS_MSVC
|
||||
// else
|
||||
// EXTRACXXFLAGS := -lstdc++
|
||||
// endif
|
||||
// else
|
||||
// ifeq ($(UNAME),Darwin)
|
||||
// EXTRACXXFLAGS := -lc++
|
||||
// else
|
||||
// ifeq ($(UNAME),FreeBSD)
|
||||
// else
|
||||
// ifeq ($(UNAME),SunOS)
|
||||
// else
|
||||
// ifeq ($(UNAME),OpenBSD)
|
||||
// else
|
||||
// EXTRACXXFLAGS := -lstdc++
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// endif
|
||||
// ```
|
||||
if is_windows() {
|
||||
if is_msvc() { vec![] } else { vec!["-lstdc++"] }
|
||||
} else {
|
||||
match &uname()[..] {
|
||||
"Darwin" => vec!["-lc++"],
|
||||
"FreeBSD" | "SunOS" | "OpenBSD" => vec![],
|
||||
_ => vec!["-lstdc++"],
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::command::Command;
|
||||
|
||||
/// Construct a gcc invocation.
|
||||
///
|
||||
/// WARNING: This assumes *a* `gcc` exists in the environment and is suitable for use.
|
||||
#[track_caller]
|
||||
pub fn gcc() -> Gcc {
|
||||
Gcc::new()
|
||||
}
|
||||
|
||||
/// A specific `gcc`.
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
pub struct Gcc {
|
||||
cmd: Command,
|
||||
}
|
||||
|
||||
crate::macros::impl_common_helpers!(Gcc);
|
||||
|
||||
impl Gcc {
|
||||
/// Construct a `gcc` invocation. This assumes that *a* suitable `gcc` is available in the
|
||||
/// environment.
|
||||
///
|
||||
/// Note that this does **not** prepopulate the `gcc` invocation with `CC_DEFAULT_FLAGS`.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
let cmd = Command::new("gcc");
|
||||
Self { cmd }
|
||||
}
|
||||
|
||||
/// Specify path of the input file.
|
||||
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||
self.cmd.arg(path.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds directories to the list that the linker searches for libraries.
|
||||
/// Equivalent to `-L`.
|
||||
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 `-o`.
|
||||
pub fn out_exe(&mut self, name: &str) -> &mut Self {
|
||||
self.cmd.arg("-o");
|
||||
self.cmd.arg(name);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify path of the output binary.
|
||||
pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||
self.cmd.arg("-o");
|
||||
self.cmd.arg(path.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
/// Optimize the output at `-O3`.
|
||||
pub fn optimize(&mut self) -> &mut Self {
|
||||
self.cmd.arg("-O3");
|
||||
self
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
mod cc;
|
||||
mod extras;
|
||||
mod gcc;
|
||||
|
||||
pub use cc::*;
|
||||
pub use extras::*;
|
||||
pub use gcc::*;
|
@ -2,8 +2,8 @@
|
||||
//! such as `cc` or `python`.
|
||||
|
||||
pub mod c_build;
|
||||
pub mod c_cxx_compiler;
|
||||
pub mod cargo;
|
||||
pub mod cc;
|
||||
pub mod clang;
|
||||
pub mod htmldocck;
|
||||
pub mod llvm;
|
||||
|
@ -46,10 +46,10 @@ pub use wasmparser;
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// Re-exports of external dependencies.
|
||||
pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc};
|
||||
pub use external_deps::{c_build, c_cxx_compiler, clang, htmldocck, llvm, python, rustc, rustdoc};
|
||||
|
||||
// These rely on external dependencies.
|
||||
pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
|
||||
pub use c_cxx_compiler::{Cc, Gcc, cc, cxx, extra_c_flags, extra_cxx_flags, gcc};
|
||||
pub use c_build::{
|
||||
build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx,
|
||||
build_native_static_lib_optimized,
|
||||
|
@ -3449,21 +3449,14 @@ impl Rewrite for ast::ForeignItem {
|
||||
ref generics,
|
||||
ref body,
|
||||
} = **fn_kind;
|
||||
if let Some(ref body) = body {
|
||||
if body.is_some() {
|
||||
let mut visitor = FmtVisitor::from_context(context);
|
||||
visitor.block_indent = shape.indent;
|
||||
visitor.last_pos = self.span.lo();
|
||||
let inner_attrs = inner_attributes(&self.attrs);
|
||||
let fn_ctxt = visit::FnCtxt::Foreign;
|
||||
visitor.visit_fn(
|
||||
visit::FnKind::Fn(
|
||||
fn_ctxt,
|
||||
self.ident,
|
||||
sig,
|
||||
&self.vis,
|
||||
generics,
|
||||
Some(body),
|
||||
),
|
||||
visit::FnKind::Fn(fn_ctxt, &self.ident, sig, &self.vis, generics, body),
|
||||
&sig.decl,
|
||||
self.span,
|
||||
defaultness,
|
||||
|
@ -390,7 +390,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
block = b;
|
||||
self.rewrite_fn_before_block(
|
||||
indent,
|
||||
ident,
|
||||
*ident,
|
||||
&FnSig::from_fn_kind(&fk, fd, defaultness),
|
||||
mk_sp(s.lo(), b.span.lo()),
|
||||
)
|
||||
@ -540,21 +540,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
ref generics,
|
||||
ref body,
|
||||
} = **fn_kind;
|
||||
if let Some(ref body) = body {
|
||||
if body.is_some() {
|
||||
let inner_attrs = inner_attributes(&item.attrs);
|
||||
let fn_ctxt = match sig.header.ext {
|
||||
ast::Extern::None => visit::FnCtxt::Free,
|
||||
_ => visit::FnCtxt::Foreign,
|
||||
};
|
||||
self.visit_fn(
|
||||
visit::FnKind::Fn(
|
||||
fn_ctxt,
|
||||
item.ident,
|
||||
sig,
|
||||
&item.vis,
|
||||
generics,
|
||||
Some(body),
|
||||
),
|
||||
visit::FnKind::Fn(fn_ctxt, &item.ident, sig, &item.vis, generics, body),
|
||||
&sig.decl,
|
||||
item.span,
|
||||
defaultness,
|
||||
@ -648,11 +641,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
ref generics,
|
||||
ref body,
|
||||
} = **fn_kind;
|
||||
if let Some(ref body) = body {
|
||||
if body.is_some() {
|
||||
let inner_attrs = inner_attributes(&ai.attrs);
|
||||
let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
|
||||
self.visit_fn(
|
||||
visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
|
||||
visit::FnKind::Fn(fn_ctxt, &ai.ident, sig, &ai.vis, generics, body),
|
||||
&sig.decl,
|
||||
ai.span,
|
||||
defaultness,
|
||||
|
@ -10,26 +10,6 @@ use crate::walk::filter_not_rust;
|
||||
const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:";
|
||||
const COMPILE_FLAGS_HEADER: &str = "compile-flags:";
|
||||
|
||||
const KNOWN_LLVM_COMPONENTS: &[&str] = &[
|
||||
"aarch64",
|
||||
"arm",
|
||||
"avr",
|
||||
"bpf",
|
||||
"csky",
|
||||
"hexagon",
|
||||
"loongarch",
|
||||
"m68k",
|
||||
"mips",
|
||||
"msp430",
|
||||
"nvptx",
|
||||
"powerpc",
|
||||
"riscv",
|
||||
"sparc",
|
||||
"systemz",
|
||||
"webassembly",
|
||||
"x86",
|
||||
];
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct RevisionInfo<'a> {
|
||||
target_arch: Option<&'a str>,
|
||||
@ -94,20 +74,6 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
|
||||
// gathered.
|
||||
}
|
||||
}
|
||||
if let Some(llvm_components) = llvm_components {
|
||||
for component in llvm_components {
|
||||
// Ensure the given component even exists.
|
||||
// This is somewhat redundant with COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS,
|
||||
// but helps detect such problems earlier (PR CI rather than bors CI).
|
||||
if !KNOWN_LLVM_COMPONENTS.contains(component) {
|
||||
eprintln!(
|
||||
"{}: revision {} specifies unknown LLVM component `{}`",
|
||||
file, rev, component
|
||||
);
|
||||
*bad = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> {
|
||||
#[no_mangle]
|
||||
pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 {
|
||||
// CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1
|
||||
// CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]]
|
||||
// CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]],
|
||||
// CHECK: [[SOME_BB]]:
|
||||
// CHECK: %[[R:.+]] = add nuw i32 %x, 1
|
||||
// CHECK: ret i32 %[[R]]
|
||||
|
13
tests/codegen/intrinsics/cold_path.rs
Normal file
13
tests/codegen/intrinsics/cold_path.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//@ compile-flags: -O
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::cold_path;
|
||||
|
||||
#[no_mangle]
|
||||
pub fn test_cold_path(x: bool) {
|
||||
cold_path();
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @test_cold_path(
|
||||
// CHECK-NOT: cold_path
|
@ -1,22 +1,35 @@
|
||||
//@ compile-flags: -C no-prepopulate-passes -Copt-level=1
|
||||
|
||||
//@ compile-flags: -O
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::{likely, unlikely};
|
||||
use std::intrinsics::likely;
|
||||
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
pub fn check_likely(x: i32, y: i32) -> Option<i32> {
|
||||
unsafe {
|
||||
// CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 true)
|
||||
if likely(x == y) { None } else { Some(x + y) }
|
||||
}
|
||||
pub fn path_a() {
|
||||
println!("path a");
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
pub fn path_b() {
|
||||
println!("path b");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn check_unlikely(x: i32, y: i32) -> Option<i32> {
|
||||
unsafe {
|
||||
// CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 false)
|
||||
if unlikely(x == y) { None } else { Some(x + y) }
|
||||
pub fn test_likely(x: bool) {
|
||||
if likely(x) {
|
||||
path_a();
|
||||
} else {
|
||||
path_b();
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @test_likely(
|
||||
// CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]]
|
||||
// CHECK: bb3:
|
||||
// CHECK-NOT: cold_path
|
||||
// CHECK: path_b
|
||||
// CHECK: bb2:
|
||||
// CHECK: path_a
|
||||
// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
|
||||
|
17
tests/codegen/intrinsics/likely_assert.rs
Normal file
17
tests/codegen/intrinsics/likely_assert.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//@ compile-flags: -O
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[no_mangle]
|
||||
pub fn test_assert(x: bool) {
|
||||
assert!(x);
|
||||
}
|
||||
|
||||
// check that assert! emits branch weights
|
||||
|
||||
// CHECK-LABEL: @test_assert(
|
||||
// CHECK: br i1 %x, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]]
|
||||
// CHECK: bb1:
|
||||
// CHECK: panic
|
||||
// CHECK: bb2:
|
||||
// CHECK: ret void
|
||||
// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
|
35
tests/codegen/intrinsics/unlikely.rs
Normal file
35
tests/codegen/intrinsics/unlikely.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//@ compile-flags: -O
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::unlikely;
|
||||
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
pub fn path_a() {
|
||||
println!("path a");
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
pub fn path_b() {
|
||||
println!("path b");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn test_unlikely(x: bool) {
|
||||
if unlikely(x) {
|
||||
path_a();
|
||||
} else {
|
||||
path_b();
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @test_unlikely(
|
||||
// CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]]
|
||||
// CHECK: bb4:
|
||||
// CHECK: path_b
|
||||
// CHECK: bb2:
|
||||
// CHECK-NOT: cold_path
|
||||
// CHECK: path_a
|
||||
// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
|
@ -1,12 +0,0 @@
|
||||
//@ known-bug: #123077
|
||||
//@ only-x86_64
|
||||
use std::arch::x86_64::{__m128, _mm_blend_ps};
|
||||
|
||||
pub fn sse41_blend_noinline( ) -> __m128 {
|
||||
let f = { |x, y| unsafe {
|
||||
_mm_blend_ps(x, y, { |x, y| unsafe })
|
||||
}};
|
||||
f(x, y)
|
||||
}
|
||||
|
||||
pub fn main() {}
|
@ -1,7 +0,0 @@
|
||||
//@ known-bug: rust-lang/rust#129150
|
||||
//@ only-x86_64
|
||||
use std::arch::x86_64::_mm_blend_ps;
|
||||
|
||||
pub fn main() {
|
||||
_mm_blend_ps(1, 2, &const {} );
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
//@ known-bug: #130687
|
||||
//@ only-x86_64
|
||||
pub struct Data([u8; usize::MAX >> 16]);
|
||||
const _: &'static Data = &Data([0; usize::MAX >> 16]);
|
@ -1,4 +0,0 @@
|
||||
//@ known-bug: #131535
|
||||
#![feature(non_lifetime_binders)]
|
||||
trait v0<> {}
|
||||
fn kind :(v0<'_, > impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {}
|
@ -1,7 +0,0 @@
|
||||
//@ known-bug: #121637
|
||||
#![feature(non_lifetime_binders)]
|
||||
trait Trait<Type> {
|
||||
type Type;
|
||||
|
||||
fn method(&self) -> impl for<T> Trait<impl Trait<T>>;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
//@ known-bug: #132530
|
||||
|
||||
#![feature(non_lifetime_binders)]
|
||||
|
||||
trait Trait<'a, A> {
|
||||
type Assoc<'a> = i32;
|
||||
}
|
||||
|
||||
fn a() -> impl for<T> Trait<Assoc = impl Trait<T>> {}
|
@ -2,6 +2,14 @@
|
||||
|
||||
//@ ignore-windows-gnu: #128981
|
||||
|
||||
// Note: u128 visualization was not supported in 10.0.22621.3233 but was fixed in 10.0.26100.2161.
|
||||
|
||||
// FIXME(#133107): this is temporarily marked as `only-64bit` because of course 32-bit msvc has
|
||||
// a different integer width and thus underlying integer type display. Only marked as such to
|
||||
// unblock the tree.
|
||||
//@ only-64bit
|
||||
//@ min-cdb-version: 10.0.26100.2161
|
||||
|
||||
// Tests the visualizations for `NonZero<T>`, `Wrapping<T>` and
|
||||
// `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`.
|
||||
|
||||
@ -48,8 +56,8 @@
|
||||
// cdb-check:nz_u64 : 0x64 [Type: core::num::nonzero::NonZero<u64>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u64>]
|
||||
|
||||
// 128-bit integers don't seem to work in CDB
|
||||
// cdb-command: dx nz_u128
|
||||
// cdb-check:nz_u128 : 111 [Type: core::num::nonzero::NonZero<u128>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u128>]
|
||||
|
||||
// cdb-command: dx nz_usize
|
||||
@ -58,101 +66,99 @@
|
||||
|
||||
// cdb-command: dx w_i8
|
||||
// cdb-check:w_i8 : 10 [Type: core::num::wrapping::Wrapping<i8>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i8>]
|
||||
// cdb-check: [+0x000] __0 : 10 [Type: char]
|
||||
|
||||
// cdb-command: dx w_i16
|
||||
// cdb-check:w_i16 : 20 [Type: core::num::wrapping::Wrapping<i16>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i16>]
|
||||
// cdb-check: [+0x000] __0 : 20 [Type: short]
|
||||
|
||||
// cdb-command: dx w_i32
|
||||
// cdb-check:w_i32 : 30 [Type: core::num::wrapping::Wrapping<i32>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i32>]
|
||||
// cdb-check: [+0x000] __0 : 30 [Type: int]
|
||||
|
||||
// cdb-command: dx w_i64
|
||||
// cdb-check:w_i64 : 40 [Type: core::num::wrapping::Wrapping<i64>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i64>]
|
||||
// cdb-check: [+0x000] __0 : 40 [Type: __int64]
|
||||
|
||||
// 128-bit integers don't seem to work in CDB
|
||||
// cdb-command: dx w_i128
|
||||
// cdb-check:w_i128 [Type: core::num::wrapping::Wrapping<i128>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i128>]
|
||||
// cdb-check:w_i128 : 50 [Type: core::num::wrapping::Wrapping<i128>]
|
||||
// cdb-check: [+0x000] __0 : 50 [Type: i128]
|
||||
|
||||
// cdb-command: dx w_isize
|
||||
// cdb-check:w_isize : 60 [Type: core::num::wrapping::Wrapping<isize>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<isize>]
|
||||
// cdb-check: [+0x000] __0 : 60 [Type: __int64]
|
||||
|
||||
// cdb-command: dx w_u8
|
||||
// cdb-check:w_u8 : 0x46 [Type: core::num::wrapping::Wrapping<u8>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u8>]
|
||||
// cdb-check: [+0x000] __0 : 0x46 [Type: unsigned char]
|
||||
|
||||
// cdb-command: dx w_u16
|
||||
// cdb-check:w_u16 : 0x50 [Type: core::num::wrapping::Wrapping<u16>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u16>]
|
||||
// cdb-check: [+0x000] __0 : 0x50 [Type: unsigned short]
|
||||
|
||||
// cdb-command: dx w_u32
|
||||
// cdb-check:w_u32 : 0x5a [Type: core::num::wrapping::Wrapping<u32>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u32>]
|
||||
// cdb-check: [+0x000] __0 : 0x5a [Type: unsigned int]
|
||||
|
||||
// cdb-command: dx w_u64
|
||||
// cdb-check:w_u64 : 0x64 [Type: core::num::wrapping::Wrapping<u64>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u64>]
|
||||
// cdb-check: [+0x000] __0 : 0x64 [Type: unsigned __int64]
|
||||
|
||||
// 128-bit integers don't seem to work in CDB
|
||||
// cdb-command: dx w_u128
|
||||
// cdb-check:w_u128 [Type: core::num::wrapping::Wrapping<u128>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u128>]
|
||||
// cdb-check:w_u128 : 110 [Type: core::num::wrapping::Wrapping<u128>]
|
||||
// cdb-check: [+0x000] __0 : 110 [Type: u128]
|
||||
|
||||
// cdb-command: dx w_usize
|
||||
// cdb-check:w_usize : 0x78 [Type: core::num::wrapping::Wrapping<usize>]
|
||||
// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<usize>]
|
||||
// cdb-check: [+0x000] __0 : 0x78 [Type: unsigned __int64]
|
||||
|
||||
// cdb-command: dx a_bool_t
|
||||
// cdb-check:a_bool_t : true [Type: core::sync::atomic::AtomicBool]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicBool]
|
||||
// cdb-check: [+0x000] v : 0x1 [Type: core::cell::UnsafeCell<u8>]
|
||||
|
||||
// cdb-command: dx a_bool_f
|
||||
// cdb-check:a_bool_f : false [Type: core::sync::atomic::AtomicBool]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicBool]
|
||||
// cdb-check: [+0x000] v : 0x0 [Type: core::cell::UnsafeCell<u8>]
|
||||
|
||||
// cdb-command: dx a_i8
|
||||
// cdb-check:a_i8 : 2 [Type: core::sync::atomic::AtomicI8]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI8]
|
||||
// cdb-check: [+0x000] v : 2 [Type: core::cell::UnsafeCell<i8>]
|
||||
|
||||
// cdb-command: dx a_i16
|
||||
// cdb-check:a_i16 : 4 [Type: core::sync::atomic::AtomicI16]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI16]
|
||||
// cdb-check: [+0x000] v : 4 [Type: core::cell::UnsafeCell<i16>]
|
||||
|
||||
// cdb-command: dx a_i32
|
||||
// cdb-check:a_i32 : 8 [Type: core::sync::atomic::AtomicI32]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI32]
|
||||
// cdb-check: [+0x000] v : 8 [Type: core::cell::UnsafeCell<i32>]
|
||||
|
||||
// cdb-command: dx a_i64
|
||||
// cdb-check:a_i64 : 16 [Type: core::sync::atomic::AtomicI64]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI64]
|
||||
// cdb-check: [+0x000] v : 16 [Type: core::cell::UnsafeCell<i64>]
|
||||
|
||||
// cdb-command: dx a_isize
|
||||
// cdb-check:a_isize : 32 [Type: core::sync::atomic::AtomicIsize]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicIsize]
|
||||
// cdb-check: [+0x000] v : 32 [Type: core::cell::UnsafeCell<isize>]
|
||||
|
||||
// cdb-command: dx a_u8
|
||||
// cdb-check:a_u8 : 0x40 [Type: core::sync::atomic::AtomicU8]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU8]
|
||||
// cdb-check: [+0x000] v : 0x40 [Type: core::cell::UnsafeCell<u8>]
|
||||
|
||||
// cdb-command: dx a_u16
|
||||
// cdb-check:a_u16 : 0x80 [Type: core::sync::atomic::AtomicU16]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU16]
|
||||
// cdb-check: [+0x000] v : 0x80 [Type: core::cell::UnsafeCell<u16>]
|
||||
|
||||
// cdb-command: dx a_u32
|
||||
// cdb-check:a_u32 : 0x100 [Type: core::sync::atomic::AtomicU32]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU32]
|
||||
// cdb-check: [+0x000] v : 0x100 [Type: core::cell::UnsafeCell<u32>]
|
||||
|
||||
// cdb-command: dx a_u64
|
||||
// cdb-check:a_u64 : 0x200 [Type: core::sync::atomic::AtomicU64]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU64]
|
||||
// cdb-check: [+0x000] v : 0x200 [Type: core::cell::UnsafeCell<u64>]
|
||||
|
||||
// cdb-command: dx a_usize
|
||||
// cdb-check:a_usize : 0x400 [Type: core::sync::atomic::AtomicUsize]
|
||||
// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicUsize]
|
||||
// cdb-check: [+0x000] v : 0x400 [Type: core::cell::UnsafeCell<usize>]
|
||||
|
||||
|
||||
// === GDB TESTS ===================================================================================
|
||||
|
@ -1,7 +1,10 @@
|
||||
// Testing the display of range types in cdb.
|
||||
|
||||
// cdb-only
|
||||
//@ min-cdb-version: 10.0.18317.1001
|
||||
//@ only-cdb
|
||||
|
||||
// FIXME(jieyouxu): triple check in CI if the directive actually works
|
||||
//@ min-cdb-version: 10.0.26100.2161
|
||||
|
||||
//@ compile-flags:-g
|
||||
|
||||
// === CDB TESTS ==================================================================================
|
||||
@ -10,23 +13,26 @@
|
||||
|
||||
// cdb-command: dx r1,d
|
||||
// cdb-check:r1,d : (3..5) [Type: core::ops::range::Range<i32>]
|
||||
// cdb-check: [<Raw View>] [Type: core::ops::range::Range<i32>]
|
||||
// cdb-check: [+0x000] start : 3 [Type: int]
|
||||
// cdb-check: [+0x004] end : 5 [Type: int]
|
||||
|
||||
// cdb-command: dx r2,d
|
||||
// cdb-check:r2,d : (2..) [Type: core::ops::range::RangeFrom<i32>]
|
||||
// cdb-check: [<Raw View>] [Type: core::ops::range::RangeFrom<i32>]
|
||||
// cdb-check: [+0x000] start : 2 [Type: int]
|
||||
|
||||
// cdb-command: dx r3,d
|
||||
// cdb-check:r3,d : (1..=4) [Type: core::ops::range::RangeInclusive<i32>]
|
||||
// cdb-check: [<Raw View>] [Type: core::ops::range::RangeInclusive<i32>]
|
||||
// cdb-check: [+0x000] start : 1 [Type: int]
|
||||
// cdb-check: [+0x004] end : 4 [Type: int]
|
||||
// cdb-check: [+0x008] exhausted : false [Type: bool]
|
||||
|
||||
// cdb-command: dx r4,d
|
||||
// cdb-check:r4,d : (..10) [Type: core::ops::range::RangeTo<i32>]
|
||||
// cdb-check: [<Raw View>] [Type: core::ops::range::RangeTo<i32>]
|
||||
// cdb-check: [+0x000] end : 10 [Type: int]
|
||||
|
||||
// cdb-command: dx r5,d
|
||||
// cdb-check:r5,d : (..=3) [Type: core::ops::range::RangeToInclusive<i32>]
|
||||
// cdb-check: [<Raw View>] [Type: core::ops::range::RangeToInclusive<i32>]
|
||||
// cdb-check: [+0x000] end : 3 [Type: int]
|
||||
|
||||
// cdb-command: dx r6,d
|
||||
// cdb-check:r6,d [Type: core::ops::range::RangeFull]
|
||||
|
@ -1,5 +1,8 @@
|
||||
//@ compile-flags:-g
|
||||
|
||||
// FIXME(jieyouxu): triple check if this works in CI
|
||||
//@ min-cdb-version: 10.0.26100.2161
|
||||
|
||||
// === GDB TESTS ===================================================================================
|
||||
|
||||
// gdb-command: run
|
||||
@ -26,18 +29,18 @@
|
||||
// cdb-check: Breakpoint 0 hit
|
||||
|
||||
// cdb-command: dx _ref
|
||||
// cdb-check: _ref : 0x[...] : () [Type: tuple$<> *]
|
||||
// cdb-check: _ref : 0x[...] [Type: tuple$<> *]
|
||||
|
||||
// cdb-command: dx _ptr
|
||||
// cdb-check: _ptr : 0x[...] : () [Type: tuple$<> *]
|
||||
// cdb-check: _ptr : 0x[...] [Type: tuple$<> *]
|
||||
|
||||
// cdb-command: dx _local
|
||||
// cdb-check: _local : () [Type: tuple$<>]
|
||||
// cdb-check: _local [Type: tuple$<>]
|
||||
|
||||
// cdb-command: dx _field,d
|
||||
// cdb-check: _field,d [Type: unit_type::_TypeContainingUnitField]
|
||||
// cdb-check: [+0x[...]] _a : 123 [Type: unsigned int]
|
||||
// cdb-check: [+0x[...]] _unit : () [Type: tuple$<>]
|
||||
// cdb-check: [+0x[...]] _unit [Type: tuple$<>]
|
||||
// cdb-check: [+0x[...]] _b : 456 [Type: unsigned __int64]
|
||||
|
||||
// Check that we can cast "void pointers" to their actual type in the debugger
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user